> >
Digital Platforms

Idempotent APIs: Retrying Requests Without Creating Duplicates

Illustration of an API request retried with the same idempotency key

Consider a fictional scenario: a portal requests a new order, but the response never arrives. Has the operation failed, or has only the reply been lost? API idempotency helps address this uncertainty, provided its guarantees are clearly defined.

A Timeout Does Not Mean the Operation Failed

From the caller’s perspective, a missing response leaves the outcome uncertain. Resending a creation request without an appropriate contract can create another order. The critical distinction is between retrying the same business intention and expressing a new one.

RFC 9110 defines idempotency through the intended effect on the server, not necessarily an identical response. PUT, DELETE and safe HTTP methods are idempotent under that definition. A client should not automatically retry a non-idempotent method unless it knows the operation is effectively idempotent or can establish that the original request was not applied.

Make the Idempotency Contract Explicit

An identifier supplied by the caller can distinguish repeated attempts from separate intentions. As the Amazon Builders’ Library explains, matching parameters alone is insufficient: two identical orders may be intentional. In the proposed contract, the caller generates a key for a business intention and reuses it for retries, rather than generating a new key after every timeout.

Document the key’s scope: which caller and operation it belongs to, how changed parameters are handled, and what response is returned when processing is underway or complete. Define how long the record remains available and what happens after expiry. Replaying a stored response is an additional contractual guarantee, not the definition of HTTP idempotency.

Handle Duplicates, Including Concurrent Requests

A key is not enough if two requests can both pass the duplicate check. For our fictional order example, keep the business write and the idempotency record within one transaction boundary. The AWS mechanism requires ACID properties for recording the token and applying the associated changes. The design must coordinate concurrent attempts so that they cannot independently create the same intended order.

The illustrative sequence is straightforward: receive the key, coordinate access to its record, create the order and record its outcome atomically, then respond. If that response is lost, a retry uses the existing record under the agreed contract. This reasoning covers the local transaction, not a chain of external services.

Stripe API v1 provides a specific example: once endpoint execution begins, it stores the first response’s status code and body, including a 500 error, for subsequent requests with the same key. Changed parameters cause an error while the key remains known. Keys may be removed once they are at least 24 hours old; reuse after removal starts a new request. These are provider-specific rules, not universal defaults.

Validate the Guarantees Before Production

Turn the contract into test scenarios, with an expected business outcome and API response for each case:

Before automating retries, review sensitive operations and formalize their guarantees, scope and limits. Use this framework to structure a design review with Halsson, without confusing a bounded idempotency contract with a promise of exactly-once execution end to end.

Back to Articles