400 Bad Request For Declined Payment
Tags: csharp, core, webdev, dotnet
Published: 2018-04-04 16:51:07

---
title: 400 Bad Request For Declined Payment
published: true
tags: csharp,core,webdev,dotnet
canonical_url: 
---

[TLDR: successful JSON post, but if credit card is declined by gateway, they return 400 bad request.  this sets off exceptions in .NET's HTTP 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 credit 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:

```c#
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](https://developers.paytrace.com/support/home#14000044372) and their sample of a declined response, it states 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, and 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, and 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 credit 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](https://msdn.microsoft.com/en-us/library/system.net.webexception.response(v=vs.110).aspx).  My adaptation of the code:

```c#
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.