A client can transmit a state-changing request, lose the response, and retry without knowing whether the first attempt committed. At that boundary, transport failure has created ambiguity rather than proof of application failure. Repeating the mutation blindly can create a second logical effect.

An idempotency key gives the server a stable operation identity across those delivery attempts. The first accepted request associates the key with an operation record. A later request carrying the same key can then reuse the recorded outcome instead of executing the mutation again.

The mechanism does not make every endpoint intrinsically idempotent. It adds a deduplication boundary whose strength depends on where the key is unique, when its record becomes durable, which request fields are bound to it, and how long the record remains authoritative.

Key scope defines the collision domain

A key is meaningful only inside a stated namespace. A random token may be unique per account, per API credential, per tenant, or across the entire service. The storage key must encode that scope consistently.

If two unrelated clients can legitimately choose the same token, a globally indexed token can merge separate operations. If the scope is too narrow in the opposite direction, retries that arrive through another credential or routing path may fail to meet the original record.

The namespace is therefore part of the API contract even when it is not visible in the token itself. A composite identity such as (tenant_id, idempotency_key) makes that boundary explicit in storage.

Random keys reduce accidental collisions when generated from a sufficiently large space, but randomness does not define semantic equivalence. The client must reuse the same key for retries of one logical operation and use a different key for a distinct operation.

Payload binding prevents key reuse from changing meaning

A repeated key can arrive with a different request body. Returning the first result without checking the new payload can conceal a client defect: the same operation identity now refers to two requested mutations.

A robust design can store a canonical request fingerprint or the relevant operation parameters beside the key. A later request with the same key is accepted as a retry only when those bound inputs match. A mismatch becomes an explicit conflict rather than a second execution or a misleading replay.

The comparison boundary must match application semantics. Hashing raw bytes can treat harmless serialization differences as different requests. Canonicalizing too aggressively can erase fields that materially change the operation. The service needs a stable representation of the inputs that define one logical mutation.

Headers can also matter. Currency, target account, authorization context, API version, or another request property may alter the permitted effect even when the JSON body is identical. Any such property belongs in the equivalence decision.

The operation record and mutation need one atomic boundary

A check-then-act sequence is insufficient when concurrent requests carry the same key:

lookup key -> absent
perform mutation
insert key

Two workers can both observe absence before either inserts the record. Both can then execute the mutation.

The deduplication decision must be serialized with the operation state at a boundary that prevents two successful owners. One common database shape uses a unique constraint on the scoped key and records operation state in the same transactional system as the business mutation.

When both records reside in one transactional database, a transaction can establish the key claim and the business change atomically. If the business effect occurs in an external system, a local transaction cannot by itself make the remote effect atomic with the key record. That design requires an additional protocol, a remote idempotency facility, or a reconciliation rule for ambiguous outcomes.

The key table is therefore not merely a response cache. It participates in concurrency control for side effects.

In-progress records need explicit retry semantics

The first request may still be executing when a retry arrives. At that moment there is no completed response to replay.

The service can reject or defer the duplicate, wait for the active operation, or return a representation of the in-progress state. Each policy exposes a different interface behavior, but all require the active record to distinguish execution from completion.

A simple state model can be expressed as:

absent -> in progress -> completed

Failure complicates the transition. If execution fails before any business effect commits, the record may be removed or marked retryable. If the effect may have committed but completion recording failed, automatically starting again can duplicate the effect. The system needs enough durable evidence to classify that state or must expose the ambiguity rather than invent certainty.

Response replay has representation boundaries

Many idempotency implementations retain the status code and response body produced by the first completed attempt. Replaying that representation can make retries stable from the client’s perspective.

Not every response field is suitable for exact replay. Time-sensitive headers, expiring credentials, streaming bodies, or representations assembled from mutable external state may require a different policy. A service can instead retain a stable operation identifier and reconstruct a current representation, but that changes the guarantee from byte-level replay to logical-operation reuse.

The contract should distinguish those models. “No second mutation” and “same HTTP response” are separate properties.

Errors also need classification. A validation error that occurs before operation ownership is established may be safe to repeat without storing it. A deterministic rejection after the key has been claimed may be worth retaining. A transient infrastructure error may permit another execution attempt only if the service can establish that no effect committed.

Retention sets the retry horizon

Idempotency records cannot usually be retained forever. Once a record expires, the same key can become indistinguishable from a new key unless another durable business identifier still blocks duplication.

That makes retention part of the observable guarantee. If records are kept for a stated interval, retries inside that interval can be deduplicated according to the service contract. A retry after expiration may execute again.

Client retry policies and server retention therefore interact. A client that can retry for longer than the server retains operation identities has a gap in duplicate protection.

Deletion also needs care around active operations. Expiring an in-progress record solely from wall-clock age can allow a second worker to acquire the same key while the original worker still runs. Active ownership needs a state or lease rule that cannot be confused with completed-record retention.

Idempotency keys do not replace domain uniqueness

Some operations already have a natural business identity. Creating an order with a caller-supplied order ID can use a unique database constraint on that ID to reject duplicates. That constraint can be stronger and longer-lived than a temporary idempotency record.

An idempotency key solves a related but different problem. It identifies one API operation across uncertain delivery. A domain identifier identifies a business entity or invariant. The two can coincide in a specific design, but treating them as interchangeable can produce awkward retention and lifecycle rules.

For example, an order ID may remain unique for the lifetime of the order domain, while an idempotency key may be retained only long enough to cover transport retries. Keeping both identities lets each enforce its own boundary.

Downstream effects can escape the local guarantee

A transaction can atomically commit a business row and an idempotency record, then trigger downstream work such as publishing an event. If publication occurs outside that transaction, process failure can leave the local mutation committed while the event remains unpublished.

The idempotency key still prevents a second local mutation, but it does not repair the missing downstream effect. Conversely, retrying downstream publication without its own stable identity can create duplicate messages.

Patterns such as a transactional outbox address this separate commit boundary by recording publication intent with the business transaction. Consumers may still require their own duplicate handling depending on the delivery semantics of the messaging system.

Idempotency is therefore compositional rather than contagious. A protected API boundary does not automatically make every downstream side effect exactly once.

Observability should follow logical operations and attempts

Transport attempts and logical operations are different counts once idempotency is present. A request metric can rise during retries while the number of committed mutations remains flat.

Useful signals include first claims, completed replays, in-progress duplicates, payload conflicts, expired-key reuse, and operation records left in ambiguous states. These measurements describe the deduplication mechanism without treating every repeated request as a new business action.

Tracing also benefits from preserving both identities. A request or trace identifier can distinguish individual delivery attempts, while the idempotency key links those attempts to one logical operation. Replacing one with the other loses information about either transport behavior or business intent.

An idempotency key converts retry ambiguity into a server-side identity decision. Its guarantee remains bounded by namespace, request equivalence, atomic persistence, active-operation handling, response policy, retention, and downstream commit boundaries. Those constraints determine whether repeated delivery remains one logical mutation or becomes another effect.