Safaricom Daraja: Duplicate json key detected - json

I am implementing Lipa na M-Pesa online by Safaricom. However, when I make the request, I get an error saying duplicate json keys detected.
The Payload:
payload = {
"BusinessShortCode": 174379,
"Password": "the password",
"Timestamp": "20220817050503",
"TransactionType": "CustomerPayBillOnline",
"Amount": 5,
"PartyA": 254714895622,
"PartyB": 174379,
"PhoneNumber": 254714895622,
"CallBackURL": "https://58fa-102-68-78-50.in.ngrok.io/api/v1/payments/callback/",
"AccountReference": "Payment",
"TransactionDesc": "Payment for K"
}
The headers:
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer access_token",
}
The request:
response = requests.request("POST", 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest', headers=headers, data=payload)
The response I get:
{
'responseId': '82699-21939686',
'responseCode': '400',
'responseDesc': 'Duplicate json key detected'
}
What could be the cause of this error and how can I go about solving it?

The issue is in the header, the request passes the Content-Type by default,
getting rid of it fixes the problem.

Although it is provided for in Safaricom's M-pesa Daraja code sample for python, Try changing this part so that it would be; renaming body=payload to json=payload
response = requests.request("POST",your-url, headers=headers, json=payload)
instead of
response = requests.request("POST", url , headers=headers, data=payload)
Removing Content-Type from the header as suggested gave me another error;
{'requestId': '12345-12345-1',
'errorCode': '400.002.02',
'errorMessage': 'Bad Request - Invalid BusinessShortCode'}
worked for me hope it does for you

The following works
import requests
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer DWbh63zkq7ZLagmNCSwnyvjA2kBQ'
}
payload = {
"BusinessShortCode": 174379,
"Password": "MTc0Mzc5YmZiMjc5ZjlhYTliZGJjZjE1OGU5N2RkNzFhNDY3Y2QyZTBjODkzMDU5YjEwZjc4ZTZiNzJhZGExZWQyYzkxOTIwMjIxMjIyMDUyOTQ5",
"Timestamp": "20221222052949",
"TransactionType": "CustomerPayBillOnline",
"Amount": 1,
"PartyA": 254712345678,
"PartyB": 174379,
"PhoneNumber": 254712345678,
"CallBackURL": "example.com/path",
"AccountReference": "CompanyXLTD",
"TransactionDesc": "Payment of X"
}
response = requests.request("POST", 'example.com/mpesa/stkpush/v1/processrequest', headers = headers, json = payload)
print(response.text.encode('utf8'))

Related

UrlFetchApp Token Authorization

I am trying to fetch a URL using GScript's UrlFetchApp. The URL requires Token API Key to be passed in request header.
url = 'https://freshsales.io/search?q=abc';
var options = {
'method' : 'get',
'headers':{
'Authorization': "Token token=XYZ"
}
};
var response = UrlFetchApp.fetch(url, options);
This does not fetch me the expected response, as pasted below:
Freshsales
window.NREUM||(NREUM={});NREUM.info={"beacon":"bam.nr-data.net","errorBeacon":"bam.nr-data.net","licenseKey":"","applicationID":"33348835,33348834","transactionName":"e11YEBQJXVlXER1LUllAVQxJFVRUQABaF0RdU0QHDg==","queueTime":1,"applicationTime":30,"agent":""}
(window.NREUM||(NREUM={})).loader_config={xpid:"VQcDVl5UDxADV1JWDwkEUw==",licenseKey:"",applicationID:"33348835"};window.NREUM||(NREUM={}),__nr_require=function(t,n,e){function
r(e){if(!n[e]){var
o=n[e]={exports:{}};t[e][0].call(o.exports,function(n){var
o=t[e][1][n];return r(o||n)},o,o.exports)}return
n[e].exports}if("function"==typeof __nr_require)return
__nr_require;for(var o=0;o0&&(p-=1)}),s.on("internal-error",function(t){i("ierr",[t,c.now(),!0])})},{}],3:[function(t,n,e){t("loader").features.ins=!0},{}],4:[function(t,n,e){function
r(t){}if(window.performance&&window.performance.timing&&window.performance.getEntriesByType){var
o=t("ee"),i=t("handle"),a=t(9),s=t(8),c="learResourceTimings",f="addEventListener",u="resourcetimingbufferfull",d="bstResource",l="resource",p="-start",h="-end",m="fn"+p,w="fn"+h,v="bstTimer",g="pushState",y=t("loader");y.features.stn=!0,t(7),"addEventListener"in window&&t(5);var x=NREUM.o.EV;o.on(m,function(t,n){var e=t[0];e
instanceof x&&(this.bstStart=y.now())}),o.on(w,function(t,n){var
e=t[0];e instanceof
x&&i("bst",[e,n,this.bstStart,y.now()])}),a.on(m,function(t,n,e){this.bstStart=y.now(),this.bstType=e}),a.on(w,function(t,n){i(v,[n,this.bstStart,y.now(),this.bstType])}),s.on(m,function(){this.bstStart=y.now()}),s.on(w,function(t,n){i(v,[n,this.bstStart,y.now(),"requestAnimationFrame"])}),o.on(g+p,function(t){this.time=y.now(),this.startPath=location.pathname+location.hash}),o.on(g+h,function(t){i("bstHist",[location.pathname+location.hash,this.startPath,this.time])}),f
in
window.performance&&(window.performance["c"+c]?window.performancef:window.performancef),documentf,documentf,documentf}},{}],5:[function(t,n,e){function
r(t){for(var
n=t;n&&!n.hasOwnProperty(u);)n=Object.getPrototypeOf(n);n&&o(n)}function
o(t){s.inPlace(t,[u,d],"-",i)}function i(t,n){return t[1]}var
a=t("ee").get("events"),s=t("wrap-function")(a,!0),c=t("gos"),f=XMLHttpRequest,u="addEventListener",d="removeEventListener";n.exports=a,"getPrototypeOf"in
Object?(r(document),r(window),r(f.prototype)):f.prototype.hasOwnProperty(u)&&(o(window),o(f.prototype)),a.on(u+"-start",function(t,n){var
e=t[1],r=c(e,"nr#wrapped",function(){function
t(){if("function"==typeof e.handleEvent)return
e.handleEvent.apply(e,arguments)}var n={object:t,"function":e}[typeof
e];return
n?s(n,"fn-",null,n.name||"anonymous"):e});this.wrapped=t[1]=r}),a.on(d+"-start",function(t){t[1]=this.wrapped||t[1]})},{}],6:[function(t,n,e){function
r(t,n,e){var r=t[n];"function"==typeof r&&(t[n]=function(){var
t=i(arguments),n={};o.emit(e+"before-start",[t],n);var
a;n[m]&&n[m].dt&&(a=n[m].dt);var s=r.apply(this,t);return
o.emit(e+"start",[t,a],s),s.then(function(t){return
o.emit(e+"end",[null,t],s),t},function(t){throw
o.emit(e+"end",[t],s),t})})}var
o=t("ee").get("fetch"),i=t(22),a=t(21);n.exports=o;var
s=window,c="fetch-",f=c+"body-",u=["arrayBuffer","blob","json","text","formData"],d=s.Request,l=s.Response,p=s.fetch,h="prototype",m="nr#context";d&&l&&p&&(a(u,function(t,n){r(d[h],n,f),r(l[h],n,f)}),r(s,"fetch",c),o.on(c+"end",function(t,n){var
e=this;if(n){var
r=n.headers.get("content-length");null!==r&&(e.rxSize=r),o.emit(c+"done",[null,n],e)}else
o.emit(c+"done",[t],e)}))},{}],7:[function(t,n,e){var
r=t("ee").get("history"),o=t("wrap-function")(r);n.exports=r;var
i=window.history&&window.history.constructor&&window.history.constructor.prototype,a=window.history;i&&i.pushState&&i.replaceState&&(a=i),o.inPlace(a,["pushState","replaceState"],"-")},{}],8:[function(t,n,e){var
r=t("ee").get("raf"),o=t("wrap-function")(r),i="equestAnimationFrame";n.exports=r,o.inPlace(window,["r"+i,"mozR"+i,"webkitR"+i,"msR"+i],"raf-"),r.on("raf-start",function(t){t[0]=o(t[0],"fn-")})},{}],9:[function(t,n,e){function
r(t,n,e){t[0]=a(t[0],"fn-",null,e)}function
o(t,n,e){this.method=e,this.timerDuration=isNaN(t[1])?0:+t[1],t[0]=a(t[0],"fn-",this,e)}var
i=t("ee").get("timer"),a=t("wrap-function")(i),s="setTimeout",c="setInterval",f="clearTimeout",u="-start",d="-";n.exports=i,a.inPlace(window,[s,"setImmediate"],s+d),a.inPlace(window,[c],c+d),a.inPlace(window,[f,"clearImmediate"],f+d),i.on(c+u,r),i.on(s+u,o)},{}],10:[function(t,n,e){function
r(t,n){d.inPlace(n,["onreadystatechange"],"fn-",s)}function o(){var
t=this,n=u.context(t);t.readyState>3&&!n.resolved&&(n.resolved=!0,u.emit("xhr-resolved",[],t)),d.inPlace(t,g,"fn-",s)}function
i(t){y.push(t),h&&(b?b.then(a):w?w(a):(E=-E,O.data=E))}function
a(){for(var t=0;t
I tested the same via python (code below) and it works perfectly.
url = "https://freshsales.io/search?q=abe"
payload = {}
headers = {
'Authorization': 'Token token=XYZ'
}
response = requests.request("GET", url, headers=headers, data = payload)
Response from Python code:
[
{
"id": "1000705745",
"name": "MKnight",
"email": "mknight#xxx.gov",
"owner": {
"id": 1000002014,
"name": "Tim"
},
"updated_at": "2020-02-13T04:57:29Z",
"primary_sales_account_name": "City of XYZ",
"type": "contact"
} ]
Any thoughts on what i may be missing here ?
Add the contentType that you can accept to force the returned content type from the server:
headers:{
Accept: "application/json",
Authorization: "Token token=XYZ"
}

{ "detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)" }

I am using django-restframework, I use postman POST json data to my project but I got the error like tittle, I have set raw and application/json here is the code from postman.
POST /account/post/reply/ HTTP/1.1
Host: localhost:8000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: a0c7bd93-631e-4c7a-8106-87f018eaf7da
{
"user": "michael",
"userid": "1",
"ihelpid": 6,
"tittle": "6",
"info": "6",
"label": "3",
"tel": "dxy970525",
"picture1": null,
"picture2": null
}
my code is really easy only like :
from rest_framework.parsers import JSONParser,ParseError
class ReplyViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list` and `detail` actions.
"""
pagination_class=PageNumberPagination
queryset = Forum_reply.objects.all()
serializer_class = ReplySerializer
#filter
filter_backends = (DjangoFilterBackend, )
filter_fields = ['postID',]
def create(self, request, *args, **kwargs):
print(request.data)
data = JSONParser().parse(request)
return HttpResponse("ok")
After I use viewsets,this error occur,I have print it on shell but it is no problem
I actually had the same error, you need to use JSON.stringify(data) like the following in case you are using ajax :
datato= {
"id" : 3,
"title" : "level up",
"author" : "jason rock"
}
$.ajax({
method:'POST',
url:"/home/api",
data : JSON.stringify(datato),
})
#SeriForte 's answer pointed me in the right way
In my case, i was not sending a correct json in the data. So please check that.
I have solved this problem,I can access data now
I changed my older code
print(request.data)
data = JSONParser().parse(request)
this will get an error. If I code like below:
print(request)
data = JSONParser().parse(request)
Then I can access data in the dictionary.
So, I did not know why but the issue is fixed
if you use a Javascript fetch request, you have to stringify the JSON Data object like so
let data = {
"key1": 1,
"key2": "text"
}
fetch(url, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify(data) // <-- do not include the Json array directly
}).then(function (response) {
// ...
console.log(response);
return response.json();
}).then(function (body) {
// ...
console.log(body);
}).catch(err => {
console.log(err)
})
If you're using postman it's not possible to put comments in the body > raw section.
Like this
So it is better to remove the commented part out.
HTH

Using Linkedin API with google apps script?

aloha all,
Im create a integration with linkedin and google apps script, for post in company page.
All is good, in terms of oauth2, i have the tokens, but the problem is the body request, look:
var payload = {"visibility": {"code": "anyone"},"comment": "Testing a full company share!","content": {"submitted-­url": "https://www.google.com","title": "Test Share with Content","description": "content description","submitted‐image-­url": "https://www.wired.com/wp-content/uploads/2015/09/google-logo.jpg"}};
var headers = {Authorization': 'Bearer ' + Service.getAccessToken()};
var options = {method:'post',headers:headers,payload:payload,muteHttpExceptions:true};
var response = UrlFetchApp.fetch("https://api.linkedin.com/v1/companies/2414183/shares?format=json", options);
THE REQUES IS GOOD, BECAUSE I USE APIGEE FOR TEST MY JSON REQUEST. THIS IS THE RESPONSE OF THE SERVER:
[16-12-12 22:38:13:411 EST] {
"errorCode": 0,
"message": "Couldn't parse share document: error: Unexpected element: CDATA",
"requestId": "XNZ80U0LCX",
"status": 400,
"timestamp": 1481600293335
}
IN SEVERAL FORUMS SAY THAT THE HEARDER I SHOUD PUT:
'Content-Type': 'application/json', 'x-li-format': 'json'
BUT WHEN PUT THIS CODE ON HEADER THE ERROR OF SERVER IS:
[16-12-12 22:40:00:344 EST] {
"errorCode": 0,
"message": "Couldn't parse Json body: Unexpected character ('v' (code 118)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: java.io.StringReader#c3576e8; line: 1, column: 2]",
"requestId": "YQFPJKZTMC",
"status": 400,
"timestamp": 1481600400231
}
THANKS ALL
For payload you need to provide valid JSON e.g.:
var payload = JSON.stringify(object):
Not:
var payload = object;
I'd also add the content type to the headers, setting it to application/json:
var options = {
'contentType': 'application/json',
'payload': JSON.stringify(payload)
};
UrlFetchApp.fetch('https://www.example.com', options);
One change... Per the Linkedin developer docs:
If you opt to provide a JSON-formatted body, make sure your HTTP request includes the following headers:
Content-Type: application/json
x-li-format: json
https://developer.linkedin.com/docs/share-on-linkedin

using Parse.Cloud.httpRequest I am unable to set correct header for AWS request?

On Parse.com, from CloudCode I need to send httpRequest to AWS (Kinesis); they are signed and it all work when sent from the browser side (extension). I have tried the following header content-type in my request in CloudCode:
"content-type": "application/json"
AWS refused it: {"Output":{"__type":"com.amazon.coral.service#UnknownOperationException","message":null},"Version":"1.0"}
"content-type": "application/x-amz-json-1.1"
parse.cloud.httprequest refused it: Result: Uncaught Error: Don't know how to convert httpRequest body Object to application/x-amz-json-1.1. To send raw bytes, please assign httpRequest body to a Buffer object containing your data.
"content-type": "application/x-www-form-urlencoded"
AWS refused it: Request failed with response code 403
AWS documentation mentions the "application/x-amz-json-1.1" content-type everywhere and I cannot see any alternative. So, I'm assuming that's the way to go, so:
How can I ask Parse.Cloud.httpRequest to send the request with this X-AMZ-JSON header but use "application/json" ‘internally’?
update: I tried to use "http" and "xmlhttp" modules taken from Node; but none of them worked—I'm happy to try any suggestions you may have.
update: this is the actual request I'm making
Parse.Cloud.httpRequest({
method: 'POST',
url: awsKinesisUrl,
headers: {
"Authorization": concat_string,
"action": "PutRecord",
"acl": "public-read",
'awsaccesskeyid': "__XXX__",
"content-type": "application/x-amz-json-1.1",
"dategenerated": date_generated+"",
"region": "eu-west-1",
"version": "2013-12-02",
"X-Amz-Date": date_generated_TZ+"",
"X-Amz-Target": "Kinesis_20131202.PutRecords"
},
body: {
body: http_req_body
},
success: function(httpResponse) {
var message = httpResponse.text;
res.render('json', {message: '{response:\''+message+'\'}' });
},
error: function(httpResponse) {
var message = httpResponse.status;
res.render('json', {message: '{response:\''+message+'\'}' });
}
});
Check out the blog post on sending raw bytes through httpRequest: http://blog.parse.com/2013/04/04/sending-bytes-from-cloud-code/
If http_req_body is a JS object, then you can use the following method call:
// Require can go at the global scope
var Buffer = require('buffer').Buffer;
Parse.Cloud.httpRequest({
method: 'POST',
url: awsKinesisUrl,
headers: {
"Authorization": concat_string,
"action": "PutRecord",
"acl": "public-read",
'awsaccesskeyid': "__XXX__",
"content-type": "application/x-amz-json-1.1",
"dategenerated": date_generated+"",
"region": "eu-west-1",
"version": "2013-12-02",
"X-Amz-Date": date_generated_TZ+"",
"X-Amz-Target": "Kinesis_20131202.PutRecords"
},
body: new Buffer(JSON.stringify(http_req_body))
}).always(function(httpResponse) {
var message = httpResponse.text;
res.render('json', {message: '{response:\''+message+'\'}' });
});
I also took the liberty of replacing your success/error callback with the newer Promise technique (http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/). This not only lets you manage several API requests more easily but let you consolidate the handlers you were rewriting for both success and error conditions.

Failed to decode JSON in HTTP request

I am using Parse Cloud Code to make a 'DELETE' HTTP Request to Delete Multiple Messages from Iron.io.
It is using exactly the same headers and url as 'GET' request to Get Message from the Queue:
headers: {
'Content-Type': 'application/json;charset=utf-8',
'Authorization': 'OAuth ' + ironToken
},
The 'GET' request does work, whether I put method: 'GET' or not inside Parse.Cloud.httpRequest().
It does work even if I send some data as body: (which are ignored).
However, for a 'DELETE' request, I need to send body:
body: {
'ids': ['someMessageId']
}
And this requests fails with very unhelpful message:
{
"status":400,"headers":
{"Access-Control-Allow-Origin":"*",
"Connection":"keep-alive",
"Content-Length":"32",
"Content-Type":"application/json",
"Date":"Tue, 06 May 2014 10:15:27 GMT"
},
"text":"{\"msg\":\"Failed to decode JSON.\"}",
"data":{"msg":"Failed to decode JSON."},
"buffer":[ ...],
"cookies":{}
}
Any idea why this happens and what else can I test?
body: {
'ids': ['someMessageId']
}
Is not valid json object. You need double quotes everywhere:
"body": {
"ids": ["someMessageId"]
}