Using Idempotency Keys

The OpenTransact REST API supports Idempotency Keys for all POST and PUT requests. This means you can prevent duplicate requests from being processed any time you are creating or updating an object using the API. This guide will walk you through how and when to use the Idemptency Key feature as well as any concerns and gotchas you may encounter when using the Idempotency Key feature.

Why Idempotency Keys?

Idempotency Keys can help make your system simpler and more reliable for your end users by preventing duplicate requests from being processed when you make calls to our API in a couple of specific situations. Usually when you make an API call you will receive a succesful response back, or some sort of validation error. Your software can process these responses and will know exactly what to do next. However, infrequently you may encounter a 500 error, or a network timeout if there is a network interruption while you are making the request. In these cases, there is no way to know whether the call to our API was successful without additional, possibly complex, queries.

By setting an Idempotency Key, you can reprocess the request anytime within 24 hours of the original request, while ensuring that an identical request is not processed twice.

Setting the Idempotency Key Header

In order to use this feature you will need to set the Idempotency-Key header on the request you are sending to our API. The value of this header should be a string that is chosen by your system and that you have a way of gauranteeing is unique.

How OpenTransact determines a match

An idempotency key will match and return a conflict response when all of the following are true:

  • The Idempotency-Key header has the same value as a previously successful request
  • The owner of the API key is the same (ex: Your Application)
  • The requests are within 24 hours of each other

Retrying Requests that Fail Validation

In our system, only successful responses will record the Idempotency Key, so if you send a request that fails for a validation reason, you can safely resend the same request.

An example:

If you are using external services to validate an account,and the account has not been moved to the active state yet. If you send a transaction using an inactive account, you will get a validation error back. If your system waits until the account is validated and retries that same request, it will successfully record the transaction along with the Idempotency Key.

Choosing an Appropriate Key & Retrying Successful Requests

Since all succesful request to our API do record Idempotency Keys, you will want to make sure to carefully choose the value that you use for the key.

An example:

Your application processes orders, and you choose to use the Order ID for the Idempotency Key value. A customer comes and pays for an order, and you successfully create a transaction in our API. Unfortunately the customer’s balance was lower than the amount you tried to process and the transaction was declined.

In this situation, you may want to contact the customer, they fix the issue with their card, and reprocess the transaction. If you re-use the same idempotency key, and your follow up request is within 24 hours, the request will fail with a conflict.

The solution is to make sure you choose a unique value for the Idempotency Key. If you want to support reprocessing, perhaps add something like a ProcessingAttempt model in your application to track each time you attempt to process an order, and use the ID from that record.

Handling the 409 Conflict Responses

There are two separate scenarios that you may need to handle when using the Idempotency Key feature. The first one may indicate a bug, or impropperly choosing a value for your key. If you send a successful request and set the Idempotency Key and then send another request with slightly different JSON paramenters, but reuse the same Idempotency-Key,s you will receive the following response:

{
  "errors": [
    {
      "title": "Idempotency Key Conflict",
      "status": "409",
      "detail": "The provided Idempotency-Key was previously used with a diferent request.",
      "code": "10019",
      "source": {
        "link": "https://api.opentransact.local:3000/v1/transactions/3570e23b-a1d0-48f5-9ead-11010fdce2fc"
      }
    }
  ]
}

The second, scenario, occurs when you send identical requests including the JSON parameters. This is what you should expect to happen if you are using this feature correctly and you have retried a request that was already successfully processed. Example:

{
  "errors": [
    {
      "title": "Idempotency Key Conflict",
      "status": "409",
      "detail": "An identical request has already been processed.",
      "source": {
        "link": "https://api.opentransact.com/v1/transactions/3570e23b-a1d0-48f5-9ead-11010fdce2fc"
      },
      "code": "10018"
    }
  ]
}

In both scenarios, the response JSON includes a link to the resource that was originally created with the given Idempotency Key. You can use this link to fetch the object for use in updating your system as necessary.