Troubleshooting

After testing payments on the test gateway, the next step is to add a production connection. If there are issues, it is almost always related to required credentials — a case of not providing the proper authentication parameters to the production gateway. Each gateway can have different requirements and their credentials can have a wide variety of naming patterns.

The best way to debug production issues is to look at the communication Spreedly had with the remote party (either a gateway or receiver). Spreedly provides full transparency via the transaction transcript.

Note: As of December 31, 2022, Spreedly only holds transaction transcripts for 90 days after the initial date of the transaction.

Using the transcript

For every Spreedly transaction that involves a remote API call, the details of that remote call are recorded as the transaction transcript. The human-readable, text-based transcript provides low-level insight into the actual details of the remote call including the request headers, body, response status:

curl https://core.spreedly.com/v1/transactions/KS3oZgWXCfFeirK16anYbijLxR/transcript \
  -u 'C7cRfNJGODKh4Iu5Ox3PToKjniY:4UIuWybmdythfNGPqAqyQnYha6s451ri0fYAo4p3drZUi7q2Jf4b7HKg8etDtoKJ'

The transcript is scrubbed of sensitive information and can be emailed to a support representative at the gateway or receiver.

The response from the gateway/receiver can help determine additional needs to get production transactions running. It may be additional fields to pass to the gateway, or different requirements for configuration settings that need to be adjusted with that provider.

For example, you may want to turn off the CVV requirement or turn off the billing address requirement if a gateway defaults to requiring them. Or, if a gateway requires a list of valid IP addresses, you may need to add Spreedly’s IP Addresses to the gateway UI.

Timeouts

It’s extremely important to us that the Spreedly API is fast. When you make a call to the API, we want to respond as quickly as possible.

The question is, how long should you wait before making the determination in your code that the Spreedly service isn’t operating as it should? Or, to put it another way, how long should you wait to determine that your application is having difficulty talking to the Spreedly service?

Let’s start by focusing on the API calls which are dependent on an external service like a payment gateway. We’re talking here about calls like purchase and authorize. You want to ensure in cases like this that you don’t set your timeout too low because if you do, that timeout could be reached before your gateway has responded. So from your application’s perspective, the transaction failed because it timed out. The reality though is that the transaction succeeded but took longer than expected to do so.

So how long is a reasonable amount of time to wait? We have seen gateways take up to 60 seconds to respond to requests when under heavy load. Therefore, when Spreedly talks to a gateway, we use an internal timeout of 61 seconds. At that point, we stop waiting for the gateway to respond and we mark the transaction as failed because we timed out talking to the gateway. This means that for your code, you’ll want to use a timeout at least a second or two more than that (perhaps 64 seconds) for the API calls which interact with a gateway. If you set your timeout for less than that, it could lead to cases where your customer has successfully paid you but your application thinks the payment has failed.

For the API calls that don’t interact with a gateway like showing a transaction or retaining a payment method, a much shorter timeout is necessary. We recommend a timeout of 5-10 seconds to determine that there’s an issue talking to the Spreedly service.

Response codes

There are multiple CVV and AVS response codes. These responses can help determine why a transaction was declined and inform next steps.

CVV response codes

AttributeDescription
DSuspicious transaction
IFailed data validation check
MMatch
NNo match
PNot processed
SShould have been present
UIssuer unable to process request
XCard does not support verification

AVS response codes

AttributeDescription
AStreet address matches, but postal code does not match.
BStreet address matches, but postal code not verified.
CStreet address and postal code do not match.
DStreet address and postal code match. Code “M” is equivalent.
EAVS data is invalid or AVS is not allowed for this card type.
FCard member’s name does not match, but billing postal code matches.
GNon-U.S. issuing bank does not support AVS.
HCard member’s name does not match. Street address and postal code match.
IAddress not verified.
JCard member’s name, billing address, and postal code match.
KCard member’s name matches but billing address and billing postal code do not match.
LCard member’s name and billing postal code match, but billing address does not match.
MStreet address and postal code match. Code “D” is equivalent.
NStreet address and postal code do not match. For American Express: Card member’s name, street address and postal code do not match.
OCard member’s name and billing address match, but billing postal code does not match.
PPostal code matches, but street address not verified.
QCard member’s name, billing address, and postal code match.
RSystem unavailable.
SBank does not support AVS.
TCard member’s name does not match, but street address matches.
UAddress information unavailable. Returned if the U.S. bank does not support non-U.S. AVS or if the AVS in a U.S. bank is not functioning properly.
VCard member’s name, billing address, and billing postal code match.
WStreet address does not match, but 9-digit postal code matches.
XStreet address and 9-digit postal code match.
YStreet address and 5-digit postal code match.
ZStreet address does not match, but 5-digit postal code matches.

JSON vs XML array structure

There are differences when sending an array of data elements in JSON versus XML. When using the XML version of an endpoint, the request body will have a parent wrapper XML element in plural form, describing what the element contains. Nested child XML elements specify the individual items of the array.

In the example below, you will see the items XML element is the parent, with one or more item XML elements.

<transaction>
  <payment_method_token>56wyNnSmuA6CWYP7w0MiYCVIbW6</payment_method_token>
  <amount>100</amount>
  <currency_code>USD</currency_code>
  <gateway_specific_fields>
    <card_connect>
      <items>
          <item>
            <line_no>1</line_no>
            <material>MATERIAL-1</material>
            <disc_amnt>0</disc_amnt>
            <unit_cost>900</unit_cost>
            <uom>CS</uom>
            <description>DESCRIPTION-1</description>
            <tax_amnt>117</tax_amnt>
            <quantity>1000</quantity>
            <upc>UPC-1</upc>
            <net_amnt>150</net_amnt>
          </item>
          <item>
            <line_no>2</line_no>
            <material>MATERIAL-2</material>
            <disc_amnt>0</disc_amnt>
            <unit_cost>900</unit_cost>
            <uom>CS</uom>
            <description>DESCRIPTION-2</description>
            <tax_amnt>117</tax_amnt>
            <quantity>1000</quantity>
            <upc>UPC-1</upc>
            <net_amnt>150</net_amnt>
          </item>
      </items>
    </card_connect>
  </gateway_specific_fields>
</transaction>

For the JSON version of an endpoint, the request body will have a parent wrapper object in plural form, describing what it contains. A child property in single form holds the array of objects.

In the example below, you will see the items JSON element is an object, with an item property which holds the array of item objects.

{
  "transaction": {
    "payment_method_token": "56wyNnSmuA6CWYP7w0MiYCVIbW6",
    "amount": 1691,
    "currency_code": "USD",
    "gateway_specific_fields": {
      "card_connect": {
        "items": {
          "item": [
            {
              "line_no": "1",
              "material": "MATERIAL-1",
              "disc_amnt": "0",
              "unit_cost": "900",
              "uom": "CS",
              "description": "DESCRIPTION-1",
              "tax_amnt": "117",
              "quantity": "1000",
              "upc": "UPC-1",
              "net_amnt": "150"
            },
            {
              "line_no": "2",
              "material": "MATERIAL-2",
              "disc_amnt": "0",
              "unit_cost": "900",
              "uom": "CS",
              "description": "DESCRIPTION-2",
              "tax_amnt": "117",
              "quantity": "1000",
              "upc": "UPC-1",
              "net_amnt": "150"
            }
          ]
        }
      }
    }
  }
}