Search code examples
delphiindy

JSON sent with Indy is not received as it is sent by Stripe API


I am sending a JSON with Indy http component to the stripe API but it is not received by the API as it is meant to be received as I receive a "Bad Request" response:

jsnObj := TJSONObject.Create;
jsnObj.AddPair('amount', TJSONNumber.Create('111')); 
jsnObj.AddPair('currency', 'eur');
jsnObj.AddPair('customer', 'cus_JNxQsqf6BoK8Rt');
jsnObj.AddPair('description', 'My First Test');
ss := TStringStream.Create(jsnObj.ToString, TEncoding.UTF8); 
rs := TStringStream.Create;
IdHTTP1.Request.BasicAuthentication := True;
IdHTTP1.Request.Username := ApiKey ;   //  test private key
IdHTTP1.Post('https://api.stripe.com/v1/charges', ss, rs);
StatusBar1.SimpleText := IdHTTP1.ResponseText;

The JSON meant to be sent is:

{
  "amount": 111,
  "currency": "eur",
  "customer": "cus_JNxQsqf6BoK8Rt",
  "description": "My First Test"
}

The API dashboard reports having received this:

{
  "{"amount":111,"currency":"eur","customer":"cus_JNxQsqf6BoK8Rt","description":"My First Test"}": null
}

The HTTP component should be making something so that it is sent this way, including a null value, maybe because of including the username in the request? With other APIs, the same HTTP component always sends what it is meant to send. The Stripe support indicates that the problem is of my side. The stripe doc specifies this:

curl -X POST  https://api.stripe.com/v1/charges \
    -u STRIPE_SECRET_KEY: \
    -d amount=2000 \
    -d currency=usd \
    -d source=tok_visa \
    -d description="Charge for [email protected]"

Does someone have any idea of where the problem is?


Solution

  • The CURL example provided in the Stripe documentation is not sending the data in JSON format at all. It is sending name=value pairs in application/x-www-form-urlencoded format instead, per the CURL documentation:

    -d, --data

    (HTTP MQTT) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to -F, --form.

    Use the TStrings overload of TIdHTTP.Post() when posting an application/x-www-form-urlencoded request, eg:

    var
      postData: TStringList;
      rs: string;
    
    ...
    
    postData := TStringList.Create;
    try
      postData.Add('amount=111'); 
      postData.Add('currency=eur');
      postData.Add('customer=cus_JNxQsqf6BoK8Rt');
      postData.Add('description=My First Test');
      IdHTTP1.Request.BasicAuthentication := True;
      IdHTTP1.Request.Username := ApiKey;   //  test private key
      rs := IdHTTP1.Post('https://api.stripe.com/v1/charges', postData);
      StatusBar1.SimpleText := IdHTTP1.ResponseText;
    finally
      postData.Free;
    end;