Design A Retry Strategy

 

When errors occur, some can be retried while others require a change before they can succeed. In the case of payments, a successful retry strategy is vital to ensure that a payment is created successfully before its associated authorization expires (7 days). Without a successful retry strategy, it is possible to receive a 5XX HTTP error on a POST /payments request and neglect to follow up and create the payment successfully with a 2XX HTTP response.

A successful retry strategy is also vital to ensure that a payment does not inadvertently get created twice.

This article will focus on retry strategies geared specifically at payments, but the strategies themselves can be generalized to all your WePay API requests.


Identify Retryable Errors

As mentioned in Clear Get Started, 5xx HTTP errors indicate that the request can be programmatically retried until successful, while 4xx HTTP errors typically require a new request.

The exception to 4XX HTTP errors requiring a new request are the THROTTLE_EXCEEDED.APPLICATION_REQUEST_THROTTLE_EXCEEDED, RESOURCE_CONFLICT, INVALID_PARAMS.CONCURRENT_UNIQUE_KEY_REQUEST_IS_PROCESSING, and INVALID_PARAMS.POINT_OF_SALE_TRANSACTION_NOT_YET_PROCESSED error codes and reasons. The THROTTLE_EXCEEDED error occurs when too many API requests have been sent in a given amount of time. As a default, we have set a rate limit per app per endpoint of 30 requests per 10 seconds. To resolve this issue reduce the rate of your requests. Learn more about API Rate Limits for Link and Clear. The INVALID_PARAMS error returns when a request is made with a Unique-Key that is still in-use on a previous request. After a request with a Unique-Key has finished processing, subsequent duplicate requests (where JSON body, parameters, headers, and all their values are exactly the same) will simply fetch the created resource. The Unique-Key error only comes into play while the initial Unique-Key is still in use. A Unique-Key is considered still in-use when the API request it was used on is still being processed and we have not responded. We limit this timeframe to 30 seconds, and will return a timeout error if we are unable to provide a response in that timeframe.

The RESOURCE_CONFLICT error appears when there are two attempts to update a legal entity at the same exact time, retry the request in the event you receive this error.

To retry a request and ensure idempotency, everything about the request must remain the same. In the case of a payment API request, "everything" includes the Unique-Key header and the request body (such as the payment method, amount, etc).

When we discuss retrying a request in this article, we refer to automatically sending the request again with no user engagement. It is important to note that 4xx errors on a payment API request may require the user to submit new payment information. That said, the submission of a new payment method will result in a new API request, so this scenario does not qualify as a retry in the context of this article.

In summary, all 5xx HTTP errors are retryable, in addition to the THROTTLE_EXCEEDED.APPLICATION_REQUEST_THROTTLE_EXCEEDED 429 error, the INVALID_PARAMS.CONCURRENT_UNIQUE_KEY_REQUEST_IS_PROCESSING 400 error, and the INVALID_PARAMS.POINT_OF_SALE_TRANSACTION_NOT_YET_PROCESSED 400 error.

Implement Retry Recommendations

First, familiarize yourself with general retry strategy recommendations below:

  • Set a maximum number of retries
    • Unique-Key headers are valid for 24 hours, so any retry thresholds you set must not retry after 24 hours from the initial request
  • Wait at least 1 second after receiving and error before the first retry
  • Implement exponential backoff for subsequent retries
  • If you do not receive a 2XX HTTP response by the time your retry logic terminates, escalate to us with the X-Correlation-Id from the response header

We also recommend progressively extending the time between retries, as this is best practice for handling web application errors.

There are a variety of ways to implement exponential back off, so use any method that suits your use case so long as the above considerations are included in your design.

As an example, your retry strategy might follow a schedule like this following the initial request:

  • 1st retry: 5 seconds
  • 2nd retry: 30 seconds after 1st retry
  • 3rd retry: 1 minute 15 seconds after 2nd retry
  • 4th retry: 4 minutes after 3rd retry
  • 5th retry: 12 minutes after 4th retry
  • 6th retry: 30 minutes after 6th retry
  • Retry every 30 minutes until 24 hours past the initial request

Understand A Retry Example

Background

A buyer purchases a cart of items to be shipped from one of your eCommerce merchants.

Payment Flow

The buyer enters their card details and then submits the payment. On your back end, you send a POST /payments request with Unique-Key, an order number, and the payment method. The request receives the UNEXPECTED_ERROR WePay API Error Code, which is a 500 HTTP error. This payment is sent through your retry flow as soon as the 500 HTTP error is received. As a result, show the buyer a payment confirmation page and indicate that a confirmation email will be sent out shortly.

Retry Flow

Your retry flow is coded to wait 1.5 seconds before sending the same request, with the same Unique-Key. On the first retry, the same API error returns, and your code will retry again 5*n seconds later where n is the number of retries thus far (with a maximum 5-minute delay).
Successful Retry FlowUnsuccessful Retry Flow
After 5 retries, you receive a 200 HTTP response. Stop retrying the payment and email the buyer that their order is complete. Notify the merchant of the purchase so that they can begin preparing for shipment.If the payment has not succeeded at 24 hours, stop retrying the payment. Email the buyer and prompt them to try using a different payment method. At the same time, fetch the X-Correlation-Id response headers from the failed requests and escalate to us.