Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Give each logical job submission one idempotency key, bind that key to the caller and the request’s meaning, and atomically associate it with one durable operation. When a client retries after a timeout or lost response, return that same operation instead of starting another job. This makes submission safely retryable within a defined retention window; it does not guarantee exactly-once effects throughout a distributed workflow.

What an idempotency key does—and does not do

HTTP idempotency describes the intended effect of repeating a request, not whether every response must be identical. RFC 9110 classifies safe methods, PUT, and DELETE as idempotent. It advises clients not to automatically retry a non-idempotent method unless they know the request is safe to repeat. A POST that starts a job is not made safe to retry merely because the client adds a header: the server must define and enforce what that key means.

For a long-running request, the key identifies one logical submission. If the client cannot tell whether its POST reached the server, it sends the retry with the original key. The service recognizes the submission and points the client to the operation already created. A deliberate request for a second job—even with the same payload—uses a new key.

This prevents duplicate job creation at the API boundary when implemented correctly. It does not ensure that every downstream effect, such as charging a payment method or sending an email, occurs exactly once. Distributed work can fail between steps, so each side-effect boundary needs its own deduplication or reconciliation strategy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Design the key and define its scope

Generate one key per intended submission

Have the client generate a high-entropy random value and reuse it for retries of that submission. Stripe recommends a V4 UUID or another sufficiently random value; its documentation also sets a 255-character maximum for keys. Those are Stripe-specific recommendations and limits, not universal HTTP requirements.

Do not generate a replacement key just because a request timed out: the server may already be working on it. Generate a new key only when the caller intends to create a separate job. Treat a key as an opaque token, not as a payload, secret, or job identifier the client can use to infer operation state.

Scope uniqueness to the API’s meaning

Define the namespace in which a key must be unique. A practical scope commonly includes the authenticated caller or tenant and the endpoint or operation class. Without caller scope, unrelated customers might collide; without operation scope, the same token could accidentally identify different kinds of work. The exact scope is an API design choice, not a schema mandated by HTTP.

Store a fingerprint of the semantically relevant request parameters with the key. If the same scoped key arrives with materially different parameters, return a clear conflict rather than silently returning an operation created for another request. Stripe documents comparing parameters against the first request and rejecting reuse with different parameters. Decide explicitly which fields are meaningful: transport details or fields that do not change the requested work should not accidentally make equivalent submissions appear different.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make key registration and job creation crash-safe

The key-to-operation association and the creation of work must not be separate, uncoordinated actions. If a service records the key and crashes before enqueueing the job, a retry may find a key that points to work that does not exist. If it enqueues first and crashes before recording the key, a retry may enqueue a duplicate.

Use a transaction or a recoverable equivalent so that a key cannot be acknowledged as accepted without a durable operation and a reliable path to execute it. One common design is to persist the idempotency record, operation record, and an outbox event in the same database transaction; a separate publisher delivers outbox events to the queue and marks them delivered. That is a design pattern, not a requirement of the cited sources. Other implementations need an equally clear recovery path for partial failure.

Enforce uniqueness in durable storage for the chosen key scope. An in-memory cache alone cannot establish durable uniqueness across process restarts or multiple service instances. On simultaneous identical requests, the uniqueness constraint or equivalent coordination should allow one request to create the operation; competing requests should resolve to that same operation. Define how the losing request loads the winner’s record rather than treating a race as an unexplained server error.

AWS guidance on distributed systems highlights why this coordination matters: retrying until confirmation supports at-least-once attempts, while sending only once risks losing work if confirmation is lost. The service must make retries safe through durable deduplication and recovery, not assume a network request and a queue write happen exactly once.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Return a durable operation resource

For work that outlives the HTTP request, return an operation identifier or resource that can be inspected later. Google’s long-running operation convention uses an operation resource that a client can poll or pass to another API to obtain the eventual result. An API can adopt that model without claiming that every service uses the same response format.

For example, an API might respond to an accepted submission with an operation URL and a state such as pending. The exact HTTP status, field names, and URL structure belong in that API’s contract. The important property is that the client can use the returned operation identity to retrieve current state and, once finished, the outcome.

Specify what duplicates receive

Document duplicate behavior for both in-progress and completed operations. One sensible asynchronous contract is to return the existing operation reference and its current state while the job is pending, then return that same reference after completion so the caller can retrieve the result. Another design can replay the original saved response. Stripe documents replaying the first saved status and body; Google’s operation model exposes the operation separately. Combining key-based deduplication with an operation resource is a design choice, not a universal standard.

Be precise about whether the duplicate response reports current state or reproduces the original acceptance response. Clients need to know whether to poll, wait, or fetch a result, and whether a retry can ever initiate new work. Avoid making response replay depend on volatile details such as a newly generated timestamp unless the contract explains that behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Define operation states, errors, and cancellation

Expose enough state to distinguish work that has not started, is running, completed, failed, or was cancelled. Keep state transitions meaningful and document which states are terminal. An operation record should make the final result or failure discoverable, so a client that lost the original response does not have to submit a new job to learn what happened.

When a duplicate key has a different request fingerprint, return a documented client error that identifies key reuse with changed parameters. When an operation is still running, return its existing identity rather than a vague “already exists” response that leaves the caller unable to continue. If the service cannot determine whether work was enqueued, surface or recover that uncertainty internally instead of creating a second operation.

Cancellation is a request to stop, not proof that work stopped. Google’s long-running operation guidance treats cancellation as best effort: the operation may have completed despite a cancellation request. Expose the operation state after cancellation is requested, and let clients inspect the final outcome.

Choose a retention window that covers uncertainty

State how long an idempotency record is retained and what happens after it expires. Stripe says keys may be pruned once they are at least 24 hours old; after pruning, reuse of the same key is treated as a new request. That is Stripe’s documented behavior, not a suitable default for every long-running job API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set the window to cover the client’s retry policy, expected queue delays, and the time needed to recover from uncertain outcomes. If a client can retry after a prolonged outage, deleting the record sooner can turn a safe retry into a new job. If job records outlive key records, document whether clients can still resolve an old key or must rely on an operation ID they saved earlier.

Retention is part of the contract: tell clients when a key stops protecting them from duplicate submission. For operations with a longer recovery horizon than the idempotency record, consider preserving a durable tombstone or another mapping long enough to prevent accidental re-creation. The chosen mechanism and duration depend on the service’s guarantees and storage policy.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Protect downstream side effects separately

A request-level key can prevent two operation records from being created for one submission. It cannot stop a worker from repeating a partial step after a crash. For each external side effect, use that provider’s idempotency mechanism where available, persist a step-level deduplication record, or reconcile the external system’s state before retrying.

For example, a job that provisions a resource may need a stable resource identity so a retried create call finds the existing resource. A payment or notification step needs its own strategy appropriate to that provider and effect. Do not describe the overall workflow as exactly once unless the claim is narrowly defined and supported by the actual guarantees at every boundary.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Evaluate storage and concurrency designs

No single storage technology is established as the correct choice. Evaluate candidate implementations against the behavior the API promises:

  • Scope: Does uniqueness apply per caller, tenant, endpoint, or another explicit namespace?
  • Atomicity and recovery: Can key registration and job creation survive crashes without stranding a key or duplicating work?
  • Concurrency: Can simultaneous requests with the same key converge on one operation?
  • Payload mismatch: Is reuse with changed parameters rejected clearly?
  • In-progress response: Does a duplicate return the operation ID and current state, block, or receive another defined response?
  • Replay: Does the service replay the original response or expose current operation state?
  • Retention: Does expiry cover retries, queue delays, and operational recovery?
  • Downstream effects: How are partial execution and external side effects deduplicated or reconciled?

An in-memory cache, relational table, key-value store, or workflow engine can only be judged against these requirements in the context of the service’s failure and recovery model. The cited guidance does not establish a preferred storage product.

A practical request lifecycle

  1. Client creates intent: Generate a random idempotency key once for the logical submission and persist it locally if the client must survive its own restart.
  2. Client submits: Send the key with the request that starts the job, along with the request parameters.
  3. Server checks identity: Resolve the authenticated caller and operation scope, then look up the key and compare the request fingerprint.
  4. Server creates or resolves work: If the key is new, atomically create the durable operation and a reliable enqueue path. If it already exists with the same fingerprint, return the existing operation. If the fingerprint differs, reject the reuse.
  5. Worker executes: Advance the operation’s observable state and apply separate deduplication or reconciliation at each side-effect boundary.
  6. Client recovers: If the submission response is lost, retry with the same key; once it has an operation identity, poll or fetch that operation instead of submitting a new job.
  7. Service expires protection: Retain the key mapping for the documented window and explain what reuse means after that window ends.

Common design failures

  • Minting a fresh key on every retry: This makes each retry look like a new intention and defeats deduplication.
  • Returning a conflict without an operation reference: The caller learns that something exists but cannot inspect or recover the work.
  • Recording the key separately from durable work creation: A crash can leave a false record or duplicate job unless the gap is recoverable.
  • Ignoring request changes: Replaying an operation for a key reused with different meaningful parameters can return the wrong result.
  • Expiring records too early: A retry after expiry may be treated as a new submission, as Stripe’s own documented post-pruning behavior illustrates.
  • Calling the whole workflow exactly once: A single submission key does not deduplicate side effects that are retried inside workers or across external services.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.