Recover is an optional paid service that enables you to automatically retry declined transactions on a backup gateway in the case of an outage or soft decline. This improves the chance that a transaction is ultimately successful and builds system resilience.

Recover will retry failed transactions in real time that Spreedly has mapped as soft declines, outages, or on customer defined custom codes.

📘

If you have interest in Recover please contact your account manager or reach out to [email protected].

Decline types and retry modes

When a transaction is declined, a gateway returns an error code that maps to a decline reason.

Error codes are specific to each payment service provider and are available in the respective gateway's documentation.

Spreedly defines and associates gateway error codes to the following three decline types:

  • Hard error code: Unlikely to be successful if retried on another gateway. This includes error codes tied to fraud suspicion, an incorrect card number, lost/stolen card, or insufficient funds.
  • Soft error code: This may be successful if retried on another gateway. This includes general error codes like do not honor, card or currency not supported.
  • Outage error code: Gateway is temporarily unavailable due to a technical issue, such as a server outage or connection timeout.

📘

See this page for the breakdown of which high-level and gateway specific codes are supported by Spreedly and how they are classified.

Spreedly has three modes of Recover: Standard, Custom, and Outage-Only:

  • Standard: Retry both soft declines and outages. Recommended for customers that want the best chance of transaction success.
  • Custom: Retry on the gateway codes that you choose. Recommended for customers who want the most control of their retry strategies.
    • This can operate in an additive mode, where you add additional codes to retry on top of the Spreedly Standard codes, or in override, where the system will only retry on user defined codes.
  • Outage-only: Retry on confirmed or suspected gateway outages only. This includes server outages, connection timeouts, and timeframes where gateway performance is degraded. Recommended for customers who may already have other retry strategies in place.

How Recover works

Spreedly customers will define the primary and up to two secondary gateways in their API request. If the primary gateway responds with a success message or an error code it is configured to allow, Recover will not send a request to the retry gateway(s).

If the primary gateway responds with a decline code or gateway outage error code, Recover will subsequently trigger a second attempt using the same transaction details on the first retry gateway, based on the mode. If the retry attempt fails on the first retry gateway for any reason, the transaction will be attempted again on the second retry gateway.

📘

Recover takes a conservative approach and manages declines as a whitelist. If a new code appears back from a gateway that has not yet been mapped, we will treat this as a hard decline and not attempt to recover.

How to use Recover

Before using Recover, you must have a minimum of one active gateway in your environment. To add a gateway to your environment, refer to the Add a Gateway guide.

Please, note that while it is possible to use Recover with a single gateway to potentially reattempt transactions, it is generally most effective to use different gateways. So we advise having a minimum of two different, active gateways in your environment to best leverage Recover.

Add Retry object via API request

When sending a purchase or an authorize request to your primary gateway, add the backup retry gateway token(s) in the transaction body in the gateway_tokens element nested within the retry element. The array can store up to two retry gateway tokens. Example:

POST /v1/gateways/{{primary_gateway_token}}/purchase.<format>HTTPS/1.1
{
  "transaction": {
    "payment_method_token": "{{payment_method_token}}",
    "amount": 100,
    "currency_code": "USD",
    "order_id": 123,
    "retry": {
     	"gateway_tokens": [
        "{{first_retry_gateway_token}}",
        "{{second_retry_gateway_token}}"
      ],
     	"mode": "standard | outage_only"
    }
  }
}
<root>
  <transaction>
    <payment_method_token>{{payment_method_token}}</payment_method_token>
    <amount>100</amount>
    <currency_code>USD</currency_code>
    <order_id>123</order_id>
    <retry>
      <gateway_tokens>{{first_retry_gateway_token}}</gateway_tokens>
      <gateway_tokens>{{second_retry_gateway_token}}</gateway_tokens>
      <mode>standard | outage_only</mode>
    </retry>
  </transaction>
</root>

Both the primary gateway and retry gateway(s) must be production gateways in the same Spreedly environment. To see all active gateways in your Spreedly environment, go to your Spreedly Dashboard and filter on the environment or use a List API call to see all created gateways in your environment.

Note that for testing purposes, it is possible to use Sandbox gateways with Recover as well, but all gateways (the primary transaction as well as all retry gateways) in such a test transaction must be non-production; if there are a mix of sandbox and non-sandbox gateways being used in this testing capacity, the first transaction will be attempted but Recover will not attempt to retry the transaction regardless of error codes. If Recover is blocked in this capacity, there will be a message detailing the context returned in the payment_snapshot.messages. See the Response structure section for more on the response object.

Including a valid retry gateway token in the transaction body of the POST request will notify Spreedly that you would like to use Recover for a Payment. If the retry gateway token is invalid, the response will return an error and the request will not execute.

The optional mode field under the retry element defaults to standard if excluded.

📘

We recommend that you send us order_id in the request, as shown in the example above, for easier reporting. Order ID is defined by a merchant and can be used to tie a customer order number to a series of transaction attempts.

Supported gateways

For Standard mode, the primary gateway must be one of the following:

The retry gateway(s) can be any one of Spreedly’s supported gateways. This includes the first retry gateway and the secondary retry gateway.

Outage Only mode does not have gateway restrictions; both the primary gateway and retry gateway can be any one of Spreedly’s supported gateways.

📘

For more details on each of the supported gateway's mapping, visit this section.

How to send gateway specific fields

Gateway-specific fields are contained within a top-level gateway_specific_fields attribute, and can be sent for transactions against certain gateways.

When using Recover, you should send all gateway-specific fields for both the primary gateway and all retry gateways. Here is an example of how to send gateway-specific fields for Recover.

{
  "transaction": {
    "gateway_specific_fields": {
      "gateway1_name": {
        "application_fee": "103",
        "receipt_email": "[email protected]"
      },
      "gateway2_name": {
        "merchant_reference": "cb76a9ffcb",
        "transfer_group": "ORDER10"
      }
    }
  }
}
<root>
  <transaction>
    <gateway_specific_fields>
      <gateway1_name>
        <application_fee>103</application_fee>
        <receipt_email>[email protected]</receipt_email>
      </gateway1_name>
      <gateway2_name>
        <merchant_reference>cb76a9ffcb</merchant_reference>
        <transfer_group>ORDER10</transfer_group>
      </gateway2_name>
    </gateway_specific_fields>
  </transaction>
</root>

How to Use Custom Error Codes

As referenced above , you can also choose to use custom error codes when using Recover. To do so, add the custom_errors key to the retry object in your request.

The custom_errors object should have the following structure:

"custom_errors": {
  "{{gateway_type}}": {
    "{{error_codes}} | {{messages}} | {{additional_data}}": [
      "custom code/message", 
      "second custom",
      "etc."
    ]
  }
}
<custom_errors>
  <{{gateway_type}}>
    <{{error_codes}} | {{messages}} | {{additional_data}}>custom code/message</{{error_codes}} | {{messages}} | {{additional_data}}>
    <{{error_codes}} | {{messages}} | {{additional_data}}>second custom</{{error_codes}} | {{messages}} | {{additional_data}}>
    <{{error_codes}} | {{messages}} | {{additional_data}}>etc.</{{error_codes}} | {{messages}} | {{additional_data}}>
    </{{gateway_type}}>
</custom_errors>

Here for example, we add a custom error code for an Adyen gateway.

{
  "transaction": {
    "payment_method_token": "{{payment_method_token}}",
    "amount": 2000,
    "currency_code": "USD",
    "retry": {
      "gateway_tokens": ["{{retry_gateway_1}}"],
      "custom_errors": {
        "adyen": {
          "messages": [
            "FRAUD-CANCELLED",
            "insufficient_funds"
          ]
        }
      }
    }
  }
}
<root>
  <transaction>
    <payment_method_token>{{payment_method_token}}</payment_method_token>
    <amount>2000</amount>
    <currency_code>USD</currency_code>
    <retry>
      <gateway_tokens>{{retry_gateway_1}}</gateway_tokens>
      <custom_errors>
        <adyen>
          <messages>FRAUD-CANCELLED</messages>
          <messages>insufficient_funds</messages>
        </adyen>
      </custom_errors>
    </retry>
  </transaction>
</root>

Shades of Custom Errors: Additive vs Override

Custom Errors in Recover can be used in one of two operating modes: additive or override

See the above section for more detail on the differences in these modes.

If custom errors are used, Recover will default to using the additive mode. However, you can use the override mode by using the override_error_codes property in the custom_errors object under the matching gateway type:

{
  "transaction": {
    "payment_method_token": "{{payment_method_token}}",
    "amount": 2000,
    "currency_code": "USD",
	  "retry": {
      "gateway_tokens": ["{{spreedly_test_gw}}"],
      "custom_errors": {
        "adyen": {
          "override_error_codes": true,
          "messages": [
            "FRAUD-CANCELLED",
            "insufficient_funds"
          ]
        }
      }
    }
  }
}
<root>
  <transaction>
    <payment_method_token>{{payment_method_token}}</payment_method_token>
    <amount>2000</amount>
    <currency_code>USD</currency_code>
    <retry>
      <gateway_tokens>{{spreedly_test_gw}}</gateway_tokens>
      <custom_errors>
        <adyen>
          <override_error_codes>true</override_error_codes>
          <messages>FRAUD-CANCELLED</messages>
          <messages>insufficient_funds</messages>
        </adyen>
      </custom_errors>
    </retry>
  </transaction>
</root>

🚧

Remember, if you use override custom errors, none of the Spreedly designated error codes or messages will be considered valid to recover a failed transaction, only the codes that you supply will be used!

Custom Errors with Stripe Gateways

Reference this page for a detailed rundown on the error codes returned by gateways and how Spreedly categorizes them, with respect to Stripe.

Using custom error codes with Stripe gateways can be a bit more complex due to the card_declined + decline_code combination, however, it is still possible to use custom codes with Stripe or StripePI gateways.

To send custom errors to be considered for usage as an error_code, the usage is simple:

{
  "transaction": {
    "payment_method_token": "{{payment_method_token}}",
    "amount": 2000,
    "currency_code": "USD",
    "retry": {
      "gateway_tokens": ["{{retry_gateway_token}}"],
      "custom_errors": {
        "stripe": {
          // these codes line up to values that could be returned in the response.error_code
          "error_codes": ["expired_card"]
        }
      }
    }
  }
}
<root>
  <transaction>
    <payment_method_token>{{payment_method_token}}</payment_method_token>
    <amount>2000</amount>
    <currency_code>USD</currency_code>
    <retry>
      <gateway_tokens>{{retry_gateway_token}}</gateway_tokens>
      <custom_errors>
        <stripe>
          <!-- these codes line up to values that could be returned in the response.error_code -->
          <error_codes>expired_card</error_codes>
        </stripe>
      </custom_errors>
    </retry>
  </transaction>
</root>

The more advanced case occurs when/if you would like to use custom errors for the decline_code value returned in the GSRF. To do this, you would add the desired custom codes to the additional_data field like so:

{
  "transaction": {
    "payment_method_token": "{{payment_method_token}}",
    "amount": 2000,
    "currency_code": "USD",
    "retry": {
      "gateway_tokens": ["{{retry_gateway_token}}"],
      "custom_errors": {
        "stripe": {
          // these codes line up to values that could be returned in `decline_code`
          "additional_data": [
            "amount_too_small",
            "insufficient_funds"
          ]
        }
      }
    }
  }
}
<root>
  <transaction>
    <payment_method_token>{{payment_method_token}}</payment_method_token>
    <amount>2000</amount>
    <currency_code>USD</currency_code>
    <retry>
      <gateway_tokens>{{retry_gateway_token}}</gateway_tokens>
      <custom_errors>
        <stripe>
          <!--these codes line up to values that could be returned in `decline_code`-->
          <additional_data>amount_too_small</additional_data>
          <additional_data>insufficient_funds</additional_data>
        </stripe>
      </custom_errors>
    </retry>
  </transaction>
</root>

Response structure

Recover introduces a new object in the API response, labeled as payment_snapshot that ties together multiple transaction attempts and includes relevant retry details.

Here is the basic structure of the payment_snapshot:

{    
  "payment_snapshot": {
    "gateway_tokens": [
      "{{primary_gateway_token}}",
      "{{retry_gateway_1_token}}",
      "{{retry_gateway_2_token}}" //optional
    ],
    "attempts": 1 | 2 | 3,
    "messages": {
      // optional //
      // used to communicate information about different Recover situations,
      // for example, falling back to outage only mode if a gateway is primary gateway is unsupported
      "retry_fallback": "The primary gateway does not support 'standard' retry mode. 'outage_only' mode will be used."
    },
    "mode": "standard | outage_only",
    "custom_error_used": true | false,
    "override_default_error_codes": true | false,
    "created_at": "2024-09-11T20:15:44Z",
    "updated_at": "2024-09-11T20:15:53Z",
    "payment_token": "{{payment_token}}",
    "previous_transaction_tokens": [
      "{{token_of_first_failed_transction}}",
      "{{token_of_second_failed_transction}}"
    ]
  },
}
<payment_snapshot>
  <gateway_tokens>{{primary_gateway_token}}</gateway_tokens>
  <gateway_tokens>{{retry_gateway_1_token}}</gateway_tokens>
  <gateway_tokens>{{retry_gateway_2_token}}</gateway_tokens> <!-- optional -->
  <attempts>1 | 2 | 3</attempts>
  <messages>
    <!-- optional
      used to communicate information about different Recover situations,
          for example, falling back to outage only mode if a gateway is primary gateway is unsupported
      -->
    <retry_fallback>The primary gateway does not support 'standard' retry mode. 'outage_only' mode will be used.</retry_fallback>
  </messages>
  <mode>standard | outage_only</mode>
  <custom_error_used>true | false</custom_error_used>
  <override_default_error_codes>true | false</override_default_error_codes>
  <created_at>2024-09-11T20:15:44Z</created_at>
  <updated_at>2024-09-11T20:15:53Z</updated_at>
  <payment_token>{{payment_token}}</payment_token>
  <previous_transaction_tokens>{{token_of_first_failed_transction}}</previous_transaction_tokens>
  <previous_transaction_tokens>{{token_of_second_failed_transction}}</previous_transaction_tokens>
</payment_snapshot>

Response Samples

Note: the following responses have much of the response body trimmed out for clarity and brevity's sake. There are many more fields that can be returned in the response.

Here is a sample response for a payment that was attempted on the primary gateway but did not proceed to the retry gateway due to a hard decline.

{ 
  "transaction": {
    "token": "transaction_token_1",
    "gateway_token": "{{primary_gateway_token}}",
    "state": "gateway_processing_failed", 
    "payment_snapshot": {
      "payment_token": "{{payment_token_identifier}}",
      "updated_at": "2024-09-11T20:15:44Z",
      "custom_error_used": false,
      "override_default_error_codes": false,
      "messages": {},
      "gateway_tokens": [
        "{{primary_gateway_token}}",
        "{{first_retry_gateway_token}}"
      ],
      "attempts": 1, //attempt = 1 indicates that only the primary gateway was attempted
      "previous_transaction_tokens": [], //empty array as this is the only attempt for the payment
      "mode": "standard"
    }
  }
}
<root>
  <transaction>
    <token>transaction_token_1</token>
    <gateway_token>{{primary_gateway_token}}</gateway_token>
    <state>gateway_processing_failed</state>
    <payment_snapshot>
      <payment_token>{{payment_token_identifier}}</payment_token>
      <updated_at>2024-09-11T20:15:44Z</updated_at>
      <custom_error_used>false</custom_error_used>
      <override_default_error_codes>false</override_default_error_codes>
      <messages></messages>
      <gateway_tokens>{{primary_gateway_token}}</gateway_tokens>
      <gateway_tokens>{{first_retry_gateway_token}}</gateway_tokens>
      <attempts>1</attempts> <!-- attempt = 1 indicates that only the primary gateway was attempted -->
      <mode>standard</mode> <!-- empty array as this is the only attempt for the payment -->
    </payment_snapshot>
  </transaction>
</root>

Here is a sample response for a payment that failed at the primary gateway with a soft decline and was retried on the first retry gateway.

{
 "transaction": {
  "token": "{{transaction_token_2}}",
  "gateway_token": "{{first_retry_gateway_token}}",
  "state": "succeeded", 
   "payment_snapshot": {
     "payment_token": "{{payment_token_identifier}}",
     "updated_at": "2023-11-13T02:14:38Z",
     "custom_error_used": false,
     "override_default_error_codes": false,
     "messages": {},
     "gateway_tokens": [
       "{{primary_gateway_token}}",
       "{{first_retry_gateway_token}}"
     ],
     "attempts": 2, //attempt = 2 indicates that only the first retry gateway was attempted
     "previous_transaction_tokens": ["{{transaction_token_1}}"], //reference to the first transaction attempt for the payment
     "mode": "standard"
   }
  ...
 }
}
<root>
  <transaction>
    <token>{{transaction_token_2}}</token>
    <gateway_token>{{first_retry_gateway_token}}</gateway_token>
    <state>succeeded</state>
    <payment_snapshot>
      <payment_token>{{payment_token_identifier}}</payment_token>
      <updated_at>2023-11-13T02:14:38Z</updated_at>
      <custom_error_used>false</custom_error_used>
      <override_default_error_codes>false</override_default_error_codes>
      <messages></messages>
      <gateway_tokens>{{primary_gateway_token}}</gateway_tokens>
      <gateway_tokens>{{first_retry_gateway_token}}</gateway_tokens>
      <attempts>2</attempts> <!-- attempt = 2 indicates that only the first retry gateway was attempted -->
      <previous_transaction_tokens>{{transaction_token_1}}</previous_transaction_tokens> <!-- reference to the first transaction attempt for the payment
     "mode": "standard" -->
      <mode>standard</mode>
    </payment_snapshot>
    ...
  </transaction>
</root>

And lastly, here is a sample response for a payment that failed at the primary gateway with a hard decline, but was retried on the first retry gateway, leveraging custom errors in an additive capacity:

{ 
  "transaction": {
    "token": "{{transaction_token_2}}",
    "gateway_token": "{{first_retry_gateway_token}}",
    "state": "succeeded", 
    "payment_snapshot": {
       "payment_token": "{{payment_token_identifier}}",
       "updated_at": "2023-11-13T02:14:38Z",
       "custom_error_used": true, // indicates that a custom error was used in the retry chain
       "override_default_error_codes": false,
       "gateway_tokens": [
         "{{primary_gateway_token}}",
         "{{first_retry_gateway_token}}"
       ],
       "attempts": 2, //attempt = 2 indicates that only the first retry gateway was attempted
       "previous_transaction_tokens": ["{{transaction_token_1}}"],
       "mode": "standard"
    }
  ...
 }
}
<root>
  <transaction>
    <token>{{transaction_token_2}}</token>
    <gateway_token>{{first_retry_gateway_token}}</gateway_token>
    <state>succeeded</state>
    <payment_snapshot>
      <payment_token>{{payment_token_identifier}}</payment_token>
      <updated_at>2023-11-13T02:14:38Z</updated_at>
      <custom_error_used>true</custom_error_used> <!-- indicates that a custom error was used in the retry chain -->
      <override_default_error_codes>false</override_default_error_codes>
      <gateway_tokens>{{primary_gateway_token}}</gateway_tokens>
      <gateway_tokens>{{first_retry_gateway_token}}</gateway_tokens>
      <attempts>2</attempts> <!-- attempt = 2 indicates that only the first retry gateway was attempted -->
      <previous_transaction_tokens>{{transaction_token_1}}</previous_transaction_tokens>
      <mode>standard</mode>
    </payment_snapshot>
  </transaction>
</root>

As you can see above, each transaction attempt includes a payment_snapshot object that contains relevant details. payment_token uniquely identifies the payment object that is shared across attempts and gateway_tokens is the array of all gateways in the configured retry chain.

attempts refers to how many times the payment has been attempted and tells the user which transaction attempt response is being referenced. For example:

  • attempts = 1 refers to the primary gateway
  • attempts = 2 refers to the first retry gateway
  • attempts = 3 refers to the secondary retry gateway

The transaction tokens for previous attempts will be included in the previous_transaction_tokens field. Lastly, it's important to note that the full transaction transcript details will be included for only the last transaction token attempted in the payment. If you would like to refer to previous tokens you may look up the previous_transaction_tokens in your Spreedly dashboard or by using a show call.

If you would like to see the full history of a payment, including full transcripts for each transaction attempt, you can call the GET payment endpoint core.spreedly.com/v1/payments/<payment_token>.json

How to test Recover using test gateways

Spreedly test gateways support the ability to trigger specific failure cases which can be used to simulate various transaction failures and the corresponding behaviors.

Users can trigger a simulated hard decline, soft decline, or gateway outage on a Spreedly Test Gateway by including the simulate_decline gateway-specific field and one of the following values: hard_decline, soft_decline, or outage, in their transaction request. If the request is sent to a non-Spreedly Test gateway, the simulate_decline gateway-specific field will be ignored.

A sample transaction request body might look as follows:

POST Request to /v1/gateways/{{test_gateway_token}}/purchase.json

POST /v1/gateways/{{test_gateway_token}}/purchase.json
{
  "transaction":{
    "payment_method_token":"{{pm_token}}",
    "amount": 9325,
    "currency_code": "USD",
    "retry":{
      "gateway_tokens":["{{first_retry_gateway_token]]"],
      "mode":"outage_only"
    },
    "gateway_specific_fields":{
    	"test":{
        "simulate_decline":"outage"
      }
    }
  }
}

When simulate_decline is included with a valid value (as noted above) the transaction will automatically fail. The mode specified by the value in simulate_decline will correspond to the error code returned by the failed transaction, and thus the action that will be taken by the Retry decision engine.

simulate_decline valueError codeRetry action taken
hard_declineinsufficient_fundsNot retried
soft_declinegeneric_declineRetried - only on standard retry mode
outagecircuit_breaker_openRetried - on both standard and outage_only modes

Note: You must have an active gateway account and a valid testing payment method with a payment service provider to test Recover outside of Spreedly’s test gateway. Refer to our testing guide for more information.

Using Recover with 3DS2

Recover supports 3DS2, however, there are some implementation details to consider.

  1. Recover will only support customers using Spreedly Global for 3DS2 authentication.
  2. Stand Alone authentication should be used, where the authentication is obtained as an independent step prior to beginning the authorize or purchaseflow with Recover parameters. In this flow, you will pass in the sca_authenitication_token obtained from the authentication step, which will be used for the 1st and any subsequent Recovery attempts.

📘

Refer to our 3DS2 Documentation here for more details on performing a Stand Alone authentication and utilizing Authentication Tokens.

FAQs

Q: Is there an extra cost to use Recover?

A: Yes, Recover is an optional paid service. Spreedly will charge a fee at the end of each monthly billing period based on a percentage of the value of the recovered transactions during the period. This fee will only be charged when a transaction initially fails and is later successful on a backup gateway using Recover.

For transactions in a currency other than USD, Spreedly uses the third-party servicer, Currencylayer, to convert and calculate the applicable fees in USD. More information about Currencylayer is available on their website at https://currencylayer.com/faq.

Q: Is there a fee for Test Transactions?

A: Spreedly will not charge for recovered transactions if they are to Spreedly Test gateway, or to Gateways in Sandbox Mode.

Q: How can I start using Recover?

A: When Test or Sandbox gateways are used, Recover does not need to be enabled by Spreedly. To enable it for Production, reach out to your account representative at Spreedly for next steps.

Q: Can I see which gateway error codes are classified as hard and soft?

A: We offer a mapping of the codes that Spreedly currently has registered as Soft (and Outage) in this document .

Q: My desired primary gateway is not supported, can I still use Transaction Retry?

A: For our Standard mode, the primary gateway must be on the list of supported gateways. If your desired primary gateway is not supported, you can either integrate with a supported gateway or contact your account manager or [email protected] to request to add support for your primary gateway.

You can use Outage-only mode for all gateways that Spreedly supports, but this will not work for gateway specific outage codes.

Q: How can I view a report of which transactions were retried?

A: Go to the ‘Smart Routing’ tab in your dashboard to run a report on which transactions were retried.

Q: Can I use Recover with stored credentials?

A: Yes, as you can send storedcredential initiator and stored_credential_reason_type in the Transaction Retry request as described in the Stored Credential Guide. If the primary or retry gateway supports Stored Credentials, then the gateway will use Stored Credentials to supplement transaction decisions. If the gateway doesn’t support stored credentials, the Stored Credentials will be ignored and the transaction will proceed as usual.

Q: Does Recover Support Network Tokenization?

A: Yes it does. While it will have the most value if all Gateways support NT, this is not required, and the NT service will automatically use PAN if one of the gateways does not support NT without disrupting the Recover attempts.

Q: Can I use Recover with any Spreedly Supported Payment Method Type?

A: Recover can support Credit Card, Apple Pay and Google Pay. However, please note your Primary and failover gateway(s) must all support these payment method types to fully complete a Recover sequence.

Q: Does Recover impact cardholders?

A: For the vast majority of transactions, there is no impact on cardholders. For the portion of transactions that are retried on another gateway, there will be a slight added latency.

In rare instances when a gateway sends us a soft error code but accepts an authorization and declines a capture, if the second gateway accepts the authorization the cardholder may see duplicate authorizations on their credit card statement.