Idempotency Keys: 8 Rules for Safer API Retries
Idempotency keys help an API recognize a repeated request so a retry does not create an unwanted extra business effect. They matter when a client loses a response and cannot tell whether a booking, order, or payment request succeeded. A well-designed key gives the client a way to ask again without treating the same intent as a new task.
This article covers eight rules for API idempotency keys: business intent, key creation, scope, request matching, concurrent calls, retention, uncertain results, and testing. It also follows a booking timeout to show why a key is useful and where its protection ends.
The problem a key solves
Imagine a portal sends a booking request. The server saves the booking, but the network drops before the portal receives the reply. However, the user sees no confirmation and clicks again. Without duplicate protection, the server may create another booking.
An idempotency key is a reference the caller reuses for the same intended operation. The server uses that reference under its contract to identify repeat attempts and return or recover the established result.
The AWS Builders’ Library article on making retries safe with idempotent APIs explains the importance of explicit caller intent. Matching requests by similar content alone cannot reliably tell a retry from a legitimate new operation.
A key does not automatically protect every action in every system. The API must support it, store the right state, and apply it correctly to the business effect.
1. Define one business intent
Start with the action the user means to perform. A single attempt to reserve a visit is one intent. Booking a second visit for another day is a new intent, even if the customer and service are the same.
This distinction prevents a common mistake: treating similar records as duplicates. Two orders with the same amount may both be valid. Conversely, one repeated request may have slightly different transport details while still representing the same intended action.
Write the rule in business language. State what starts an intent, when it ends, and what change requires a fresh one. The client and server teams need the same understanding.
Our article on REST API design explains the broader request contract. Idempotency belongs in that contract, alongside outcomes, errors, and concurrency.
2. Create the key before the uncertain call
The caller needs a durable key before it sends the consequential request. If it creates a new key after every timeout, the server sees a series of new operations rather than retries.
Keep the key with the pending work so the client can reuse it after a refresh, restart, or retry, where that behavior is in scope. A value held only in a short-lived screen state may disappear at the moment the user needs it.
Use a generation method that makes accidental collisions suitably unlikely for the system. Do not use an amount, email address, or timestamp alone as a convenient substitute without a sound uniqueness design.
Also avoid placing personal data or secrets in keys. Logs and support tools may record them. An opaque reference usually serves the purpose with less exposure.
3. Set the scope of uniqueness
A key’s meaning depends on its scope. The same value might be valid for different accounts or endpoints if the API contract separates them. Another API may use a broader namespace.
Therefore, document what combines with the key to identify the operation. Common factors include the authenticated caller, tenant, and operation type. The correct scope should prevent one caller from receiving another caller’s result.
Test that boundary explicitly. If two customers use the same key value, their actions and responses must follow the intended isolation rules. A key should never become a shortcut around authorization.
For a business with several legal entities, also check account routing. Duplicate protection in one payment or order account does not necessarily apply to another.
4. Reject conflicting reuse of the same key
A repeat attempt should represent the same intended request. If the caller reuses a key with a changed amount, site, or service, the server needs a clear policy. Quietly accepting the new details can hide a serious client error.
Many designs compare relevant request parameters with the earlier attempt and report a conflict when they differ. The exact behavior depends on the provider. Read the current API’s contract rather than assuming one universal rule.
For example, Stripe’s idempotent request reference is the place to check its provider-specific behavior. Apply the same habit to each connected API: supported methods, key scope, retention, and response handling can differ.
Define how the user can intentionally change a request. A revised booking may need a new operation or an update to an existing record, not a retry with a reused key.
5. Handle overlapping attempts atomically
Two copies of a request can arrive at nearly the same time. A weak implementation checks for the key, sees nothing, and lets both copies act before either records the result.
Ask the developer how the server claims the key and coordinates it with the business write. The design needs a reliable way to prevent both workers from creating separate effects for the same intent.
Also define the response while work remains in progress. The second caller may wait, receive a pending result, or receive a response that tells it when to retry. Whatever the policy, the client must understand it.
Test overlapping requests deliberately. Sequentially sending the same call twice does not prove the design handles concurrency. The timing that matters is when both attempts compete before the first finishes.
6. Make retention and expiry explicit
The server cannot be assumed to remember every key forever. A provider may keep records for a defined window or apply other lifecycle rules. After that window, a reused key may no longer receive the same treatment.
Match client retry behavior to the documented policy. A background worker that resumes after a long outage may need to check the business record before sending an old intent again.
Keep a durable business reference where the workflow needs long-term reconciliation. An idempotency store often solves a retry problem; it should not be the only evidence that a booking or payment exists.
Also plan cleanup carefully. Removing key state while an operation remains uncertain can weaken duplicate protection. Retention rules should account for processing time, retries, and the provider’s actual behavior.
7. Separate request safety from business completion
A recognized key does not necessarily mean the entire business journey finished. The API may have created a pending operation that later succeeds or fails. The client still needs to follow the supported status path.
For example, a payment request can have several states before the business treats it as settled. A booking may wait for a downstream scheduling decision. Show those states instead of translating every accepted response into final success.
Our article on event driven architecture explains how background work creates separate completion points. Duplicate protection should extend to relevant downstream consumers too.
If the result remains unknown, provide a review route. Staff should search by the stable business reference and follow an approved recovery process rather than invent a fresh request merely to see what happens.
8. Test failure at the point of uncertainty
A useful test loses the response after the server commits the action. The client then retries with the same key. Confirm the number of business effects, not just the HTTP response.
Also test failures before processing, during processing, and after a partial downstream handoff. These states may follow different rules in the chosen API.
Include restart and expiry scenarios where they matter. A design that works only while one process holds data in memory may fail after a server or client restart.
Finally, inspect support evidence. Staff should be able to connect the key, request reference, business record, and outcome without seeing secrets or excessive personal data.
A booking timeout from the user’s view
Imagine a customer chooses a maintenance slot. The portal creates a request reference and key, then sends the booking details. It disables casual repeated clicks, but the API remains responsible for duplicate protection.
The server checks access, validates the details, claims the key under its supported design, and creates the booking. The response disappears. Instead, the portal shows that confirmation is still pending rather than declaring failure with certainty.
Next, the portal retries the same intent with the same key. The server returns the established result or the documented in-progress response. The portal then shows the confirmed booking once it has evidence.
Now the customer wants another visit. The portal starts a new intent with a new key. It does not reuse the first key merely because the same customer and service are involved.
Finally, an outage lasts beyond the provider’s key retention window. The support process checks the stable booking reference before attempting recovery. This protects against treating an old unknown outcome as a clean new request.
What idempotency keys do not replace
They do not replace authorization. A caller must still have permission to perform the action and view the returned result. Nor do they validate prices, capacity, or business state on their own.
They also differ from locking a record or checking its version. Those controls can prevent conflicting edits, while idempotency focuses on repeat attempts for the same intent. A workflow may need both.
Our article on data synchronization explains other controls for repeated and conflicting updates. Choose each control for the specific failure it addresses.
Avoid promising “exactly once” across a whole distributed process merely because one endpoint supports a key. Every boundary and external effect needs its own evidence.
Questions for an API supplier
Ask which operations accept keys, how the provider scopes them, and how it handles changed parameters. Request the retention policy and the response for a repeated call while the first still runs.
Then ask what the client should do after a timeout, a server error, or a long outage. The answer should reference supported recovery behavior, not a general promise that retries are safe.
For a custom API, write these rules before implementation. The consumer team needs enough detail to build a correct pending state and retry policy. A header name without behavior is not a complete contract.
Frequently Asked Questions
Should a retry use a new idempotency key?
For the same intended operation, use the same key under the API’s contract. A fresh key can tell the server that the caller wants a new operation.
Can two valid orders have the same details?
Yes. Similar content does not prove shared intent. Separate legitimate orders need their own identities and keys.
Do keys prevent every duplicate payment?
No universal guarantee applies. Protection depends on the endpoint, scope, retention, implementation, and any downstream effects.
What if the key has expired?
Follow the provider’s recovery policy. Check durable business references and the existing outcome before sending a request that could create another effect.
Tie every retry to a clear intent
Idempotency keys help when clients preserve intent and servers enforce a precise contract. Define scope, concurrency, retention, and recovery before release. Then test a lost response after a committed action so the team can prove that retrying does not create unwanted extra work.
Build software around how your business works
Design safe API writes and recovery paths for bookings, orders, and other important workflows.