I am trying to do a POST request on my flutter application using the Http package. I tested my request first on the Api sandbox website, and then in Postman. It works well there, but once in Flutter, I always get a 400 Bad Request.
Here is my code in Flutter:
import 'package:http/http.dart';
import 'package:uuid/uuid.dart';
import 'package:wave_app/env/secrets.dart';
import 'package:wave_app/models/momo_token.dart';
String url = "https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay";
var uuid = Uuid();
String requestId = uuid.v4();
MomoToken token = await _createMomoNewTokenCollection();
String auth = "Bearer " + token.accessToken;
Map<String, String> headers = {
"Authorization": auth,
"X-Target-Environment": "sandbox",
"X-Reference-Id": requestId,
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": momoCollectionSubscriptionKey
};
String jsonBody = '{"amount": "5","currency": "EUR", "externalId": "123", "payer": {"partyIdType": "MSISDN","partyId": "46733123454"}, "payerMessage": "tripId-123456","payeeNote": "driverId-654321"}';
Response response = await post(url, headers: headers, body: jsonBody);
int statusCode = response.statusCode;
print("STATUS CODE REQUEST TO PAY " + statusCode.toString());
print(response.reasonPhrase.toString());
print(response.body.toString());
if (statusCode == 202) {
return response.body.toString();
} else {
return null;
}
}
The api doc is here: https://momodeveloper.mtn.com/docs/services/collection/operations/requesttopay-POST?
And here is the code in curl of my Postman request (using the same variable above requestId, auth, momoCollectionSubscriptionKey)
curl --request POST \
--url https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay \
--header 'Accept: */*' \
--header 'Accept-Encoding: gzip, deflate' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6IjFmY2MzMjBhLTM0NWQtMTFlYS04NTBkLTJlNzI4Y2U4ODEyNSIsImV4cGlyZXMiOiIyMDIwLTAxLTExVDE1OjU3OjE4Ljc3NyIsInNlc3Npb25JZCI6ImZmYzc1OGE2LTM2MWEtNDM4ZS1hYjE5LWQ1ZGQ4ZmU4ZjEyOSJ9.DeoJyU6Hb0he_or1XeBxW-6s-xwdtmi0cUrYjQe0Z796bIGvvT-VJ214JaZItG-CBQpgv7dHbLfXNqr8D05Q7U9XiOtpr8mtYWQlY-MseGIHAyxp1qBuQkwjmBYBlDxQOYYfzG9SZ8tGFUI1_k59LMNYIhDlXXKa68Ym1sylZ8wfWjGuHaKVzMEH25ubiBwCLev5IHPchuF3toVP99U-HC8t95E3zrEt9dHgzn0hnwvpB31wcsu_b3vb-YZ1idHgosPc2GmKFsDruX14VniKBicCsnGHqZAkSPXwaOR6SIn4JZEEwhAIj3Oe2H5dwxloiX5rzaApdkwEg6KSoBXk8A' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header 'Content-Length: 194' \
--header 'Content-Type: application/json' \
--header 'Host: sandbox.momodeveloper.mtn.com' \
--header 'Ocp-Apim-Subscription-Key: 281eb****************' \
--header 'Postman-Token: ece19062-1f0b-4873-a3ed-1bd4ada8746a,528004b2-410d-4653-9909-5197a3dc95db' \
--header 'User-Agent: PostmanRuntime/7.20.1' \
--header 'X-Reference-Id: 062f8aad-f529-4d0a-804c-affb888c2b8b' \
--header 'X-Target-Environment: sandbox' \
--header 'cache-control: no-cache' \
--data '{\r\n "amount": "5",\r\n "currency": "EUR",\r\n "externalId": "123",\r\n "payer": {\r\n "partyIdType": "MSISDN",\r\n "partyId": "46733123454"\r\n },\r\n "payerMessage": "hi",\r\n "payeeNote": "hi"\r\n}'
On postman and their website, I always get a 202 Accepted response.
I am not sure, what I'm doing wrong here. Any help would be greatly appreciated!
------------ EDIT -------------------
I also tried with HttpClient, here is the code, but still got 400 Bad Request
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set("Authorization", "Bearer " + token.accessToken);
request.headers.set('content-type', 'application/json');
request.headers.set("X-Target-Environment", "sandbox");
request.headers.set("X-Reference-Id", requestId);
request.headers.set("Ocp-Apim-Subscription-Key", momoCollectionSubscriptionKey);
request.add(utf8.encode(jsonBody));
HttpClientResponse response = await request.close();
print("STATUS CODE " + response.statusCode.toString() + " " + response.reasonPhrase);
String reply = await response.transform(utf8.decoder).join();
print("REPLY " + reply);
httpClient.close();
This is definitely a problem with the server. The two headers X-Reference-Id and X-Target-Environment are being handled case sensitively by the server (i.e. it is not in compliance with the RFC).
It's Dart's io.HttpClient that forces headers to lower case, so this affects package:http and package:dio which both rely on it. There's a request to allow the client to preserve the case of headers but it's coming slowly as it's a breaking change.
In the meantime, try using this fork of the client which preserves header case. https://pub.dev/packages/alt_http/
Solved same issue by changing jsonBody from String into Map.
String jsonBody = '{"amount": "5","currency": "EUR", "externalId": "123", "payer": {"partyIdType": "MSISDN","partyId": "46733123454"}, "payerMessage": "tripId-123456","payeeNote": "driverId-654321"}';
Only solved when changed from String -> Map;
Map jsonBody = {"amount": "5","currency": "EUR", "externalId": "123", "payer": {"partyIdType": "MSISDN","partyId": "46733123454"}, "payerMessage": "tripId-123456","payeeNote": "driverId-654321"};
and additionally, included the jsonEncode
Response response = await post(url, headers: headers, body: jsonEncode(jsonBody));
jsonEncode requires the import of Convert library
import 'dart:convert';
Related
I'm trying to get the access token on Postman. I'm in "Get acces token", "body" and I'm using the 'POST' method (not the 'GET' one). When I click on the "send" button, I read this message:
{
"timestamp": "2022-11-07T21:26:28.119+00:00",
"status": 401,
"error": "Unauthorized",
"message": "",
"path": "/oidc/accessToken"
}
I think the problem is my oauth2 url. I didn't understand how to get one. I read on the internet that the url should be like this:
https://id:secret#mywebsite.com
Is it correct? I doesn't work for me.
How could I write a correct oauth2 url?
Thank you in advance!
PS: the 'code snippet' is this one:
curl --location --request POST 'https://link/accessToken' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'APIM-Debug: true' \
--data-urlencode 'client_id=' \
--data-urlencode 'client_secret=' \
--data-urlencode 'username=myusername' \
--data-urlencode 'password=mypassword' \
--data-urlencode 'grant_type=client_credentials'
I'm trying to use POST methods (Revenue REST API) but I always get the error message "Content-Type not application/json".
The strange is that I'm using their website to test: [https://docs.revenuecat.com/reference#receipts][1]
API TEST (IMAGE)
curl --request POST \
--url https://api.revenuecat.com/v1/receipts \
--header 'Accept: application/json' \
--header 'Authorization: Bearer xxxx' \
--header 'Content-Type: application/json' \
--header 'X-Platform: android' \
--data '
{
"product_id": "xxxx",
"price": 12.9,
"currency": "BRL",
"is_restore": "false",
"app_user_id": "xxxx",
"fetch_token": "xxxxxx"
}
'
Any clues?
I've run the code using CURL and it works. Problem was in revenuecat website.
Their API test page has a bug. It adds an extra Content-Type: application/json
header to the request. You can see it the Metadata tab
Request Headers
Accept: application/json
Content-Type: application/json
X-Platform: stripe
Content-Type: application/json
Authorization: Bearer ********************
User-Agent: ReadMe-API-Explorer
And sends the request with an invalid header (you can check it in your browsers network traffic):
content-type: application/json, application/json
I am trying to complete a checkout with the /checkout API integrated with Stripe, following this documentation: https://shopify.dev/tutorials/complete-a-sales-channel-payment-with-checkout-api#integrate-stripe-wi...
I am getting this response on my final request:
Request:
curl --location --request POST 'https://<nameofmyshop>.myshopify.com/admin/api/2021-04/checkouts/<shopify-checkout-token>/complete.json' \
--header 'Content-Type: application/json' \
--header 'X-Shopify-Access-Token: <shpat_shopify-access-token>' \
--data-raw '{
"payment": {
"amount": "1.00",
"unique_token": "unique token I made",
"payment_token": {
"payment_data": "<tok_stripe-vault-token>",
"type": "stripe_vault_token"
},
"request_details": {
"ip_address": "123.1.1.1",
"accept_language": "en",
"user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.98 Safari\/537.36"
}
}
}'
(error) Response:
422 Unprocessable Entity
{
"errors": {
"base": [
{
"code": "missing_transactions",
"message": "Cannot complete the checkout without any transactions.",
"options": {}
}
]
}
}
Some details about my Shopify Shop, and Stripe setup:
I have Shopify Payments enabled
test mode is on
I successfully placed an order though the shop's website with CC# 4242 4242 4242 4242
I have a test Stripe Connect account for my "customer"
I can successfully get a Stripe token generated for the customer
Here is my flow:
create a checkout POST https://{{store_name}}.myshopify.com/admin/api/{{api_version}}/checkouts.json
Save checkout.token, and checkout.shopify_payments_account_id from the response
Get Stripe token for customer:
curl --location --request POST 'https://api.stripe.com/v1/tokens' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Stripe-Account: {{shopify_payments_account_id}}' \
--header 'Authorization: Bearer {{stripe-token}}' \
--data-urlencode 'customer=<cus_customers-stripe-connect-id>'
save id from response "id: <tok_stripe-vault-token>"
complete checkout with Stripe token (request above)
Should we be able to complete a checkout using Shopify /checkout API + Stripe-Connect Test Accounts?
Thank you for any help!
I was using the wrong endpoint:
final request should go to /payments.json, not /complete.json
url --location --request POST 'https://<nameofmyshop>.myshopify.com/admin/api/2021-04/checkouts/<shopify-checkout-token>/payments.json' \
--header 'Content-Type: application/json' \
--header 'X-Shopify-Access-Token: <shpat_shopify-access-token>' \
--data-raw '{
"payment": {
"amount": "1.00",
"unique_token": "unique token I made",
"payment_token": {
"payment_data": "<tok_stripe-vault-token>",
"type": "stripe_vault_token"
},
"request_details": {
"ip_address": "123.1.1.1",
"accept_language": "en",
"user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.98 Safari\/537.36"
}
}
}'
i have a curl request like this
curl -X POST \
http://0.0.0.0:8080/auth/realms/nestle/authz/protection/uma-policy/b952ad68-d23b-46ab-a456-b8598f4ffb28 \
-H 'Authorization: Bearer '{token} \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"name": "Any people manager",
"description": "Allow access to any people manager",
"scopes": ["read-private"],
"roles": ["manager"]
}'
i want to convert it into the httpRequest
for that i am doing something like this
val uri: String = "http://0.0.0.0:8080/auth/realms/nestle/authz/protection/uma-policy/"+resourceID
val authorization = headers.Authorization(OAuth2BearerToken(pat))
val uri: String = "http://0.0.0.0:8080/auth/realms/nestle/authz/protection/uma-policy/" + resourceID
val authorization = headers.Authorization(OAuth2BearerToken(pat))
val jsonStr =
"""{
| "name": "Any people event-manager 2",
| "description": "Allow access to any people event manager",
| "scopes": ["read-private"],
| "roles": ["manager","interpret/event_manager"]
| }"""
val request = HttpRequest(HttpMethods.POST, uri, List(authorization), HttpEntity(ContentTypes.`application/json`, jsonStr.stripMargin.parseJson.toString()))
how can i set -H 'Cache-Control: no-cache' \ in the above code ?
-H 'Cache-Control: no-cache' is a header , so it should be in the 3rd parameter of HttpRequest
final class HttpRequest(
val method: HttpMethod,
val uri: Uri,
val headers: immutable.Seq[HttpHeader],
val entity: RequestEntity,
val protocol: HttpProtocol)
Try something like
val request = HttpRequest(
HttpMethods.POST,
uri,
List(authorization, `Cache-Control`(`no-cache`)),
HttpEntity(ContentTypes.`application/json`, jsonStr.stripMargin.parseJson.toString())
)
The documentation and help for this particular Segment.io is limited and sparse, so I hope it's OK to ask in here.
I have just set up a Segment.io workspace and a HTTP API source
Per the docs, I sent some POST requests (with Postman) to the https://api.segment.io/v1/track and https://api.segment.io/v1/page endpoints. The requests were structured like this:
curl -X POST \
https://api.segment.io/v1/track \
-H 'Accept: */*' \
-H 'Authorization: My4w3s0m3k3y' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Host: api.segment.io' \
-H 'Postman-Token: 474d7fbe-15af-43d2-b629-61e15945e662,2c3d5fbe-2c09-4fe6-b7ea-a04e3221201b' \
-H 'User-Agent: PostmanRuntime/7.11.0' \
-H 'accept-encoding: gzip, deflate' \
-H 'cache-control: no-cache' \
-H 'content-length: 117' \
-d '{
"userId": "abc123",
"event": "My tests",
"properties": {
"name": "test 1"
}
}'
which all returned a 200 response and the following message:
{
"success": true
}
However, when I got to my dashboard, no events have been recorded.
The debugger is also empty
What am I missing here?
It looks like your write key isn't base64 encoded. When you encode your write key, remember to add the : at the end of it, before it's encoded.
Also, for the Authorization key:value, be sure to add Basic before the encoded write key. So your Authorization key:value would look like:
Authorization: Basic {encoded write key}
An example from the segment documentation:
In practice that means taking a Segment source Write Key,'abc123', as the username, adding a colon, and then the password field is left empty. After base64 encoding 'abc123:' becomes 'YWJjMTIzOg=='; and this is passed in the authorization header like so: 'Authorization: Basic YWJjMTIzOg=='.
I have been dealing with the same issue.
I found the solution as Todd said.
You should add a header Authorization: Basic + base64 encoding write key.
So, you look for the Segment source setting and get the write key.
After that, i have used an online base64 encoding tool to encode my write key.
Finally, you should add this header (Authorization) with 'Basic' and the encoded write key.
You should be able to see the tracked event in the Debugging panel in Segment web page.
I hope this helps!
You can try this code
const { promisify } = require("util");
var Analytics = require("analytics-node");
var analytics = new Analytics("xxxxxxxxxxxxxxxxxxxxxxx", {
flushAt: 1,
});
const [identify, track] = [
analytics.identify.bind(analytics),
analytics.track.bind(analytics),
].map(promisify);
console.log("user id: ", req.body.event.app_user_id);
let app_user_id = req.body.event.app_user_id;
let period_type = req.body.event.period_type;
let expiration_at_ms = req.body.event.expiration_at_ms;
let ret = "Initial";
try {
await identify({
userId: app_user_id,
traits: {
period_type: period_type,
expiration_at_ms: expiration_at_ms,
},
});
ret = "Done : Sengment done";
} catch (err) {
console.log("err: ", err);
ret = "Error : " + err;
}
return {
rafsan: ret,
};
Try to clear your browser's cache or use a different browser. I had the same problem and worked for me.
Hope this helps.