PayTrace: 400 Bad Request For Declined Payment

TLDR:  post IS successful.  PayTrace, by design, returns a 400 error, which sets off exceptions in httpresponse.  Solution: catch the exception and then continue deserializing your response.

I coded a few weeks ago a .NET post to the PayTrace API which helps me demo and test payment by credit card using client side encryption.  The process more or less went like this:

  • Create demo account as a merchant on Paytrace
  • Download PEM key
  • On submit of form with credit card information, an imported PayTraceJS library encrypts the card number and csc code
  • Use the demo account’s username and password to submit a request for a token
  • Submit transaction (which includes encrypted info as well as other required fields) using token and await response

A successful http response returns a status code of 200.  I read it via stream, deserialize it using json into my CardResponse object (both successful and failure responses have the same design).  Everything went great until I began testing rejected cards.

My initial demo code that worked lovely when the response was 200 looked something like this:

var httpResponse  = (HttpWebResponse)req.GetResponse();

using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
  string result = streamReader.ReadToEnd();
  creditCardResponse = JsonConvert.DeserializeObject<CardResponse>(result);
}

 

The problem is that when a card is rejected (either for lack of funds, bad address, whatever the reason) the http response status code changes from 200 to 400 “Bad Request”.  This causes an immediate exception to be thrown on the first line in the sample above.  Even worse, the 400 code is a bit misleading because my initial thought was my JSON request was malformed.  I was missing a required field, maybe?  No.

This is by PayTrace design. 

If you check their documentation and sample of a declined response, it says clearly: “Following response will be returned with a HTTP Status 400 Bad Request.

I initially tested this by going through debug mode, going as far as getting the token (I obviously was hitting the PayTrace wall and passing auth to get a Bad Request instead of Not Authorized).  Then, I grabbed the token out of my debug session, ran a few more lines, got the JSON of my HttpRequest.   I gathered all info I needed for the request and threw it into Postman.  Postman came back with a JSON string with all the details I needed:  success (failed), response message, etc etc.  I’d narrowed the problem directly linked to how I was bringing that response into .NET HttpResponse.

So what now?  My HttpResponse was failing immediately on the 400, meaning I couldn’t dig into and read the stream, much less get the reasons why this particular card was declined.

My first attempts I tried simple try/catches, but didn’t get it just right until I captured that particular web exception.  My adaptation of the code:

try
{
  HttpWebResponse response = (HttpWebResponse)req.GetResponse();

  using (var streamReader = new StreamReader(response.GetResponseStream()))
  {
    string result = streamReader.ReadToEnd();
    creditCardResponse = JsonConvert.DeserializeObject<CardResponse>(result);
  }
}
catch (WebException ex)
{
  using (WebResponse resp = ex.Response)
  {
    using (Stream data = resp.GetResponseStream())
    {
      StreamReader sr = new StreamReader(data);
      string result = sr.ReadToEnd();
      creditCardResponse = JsonConvert.DeserializeObject<CardResponse>(result);
    }
  }
}

 

I’ll have to modify this for other sorts of responses (not 200 or 400), but it was the push I needed to get over this one.  I was able to deserialize the failed response into my CardResponse object and report a failure with reasons why.

You may also like