By the Octri team · Updated
What is an idempotency key? How it works, with examples
A client sends a request, the server creates an order, and the response is lost. From the client's perspective the request failed. From the server's perspective it succeeded. That gap is why retries of payment and order operations need more than optimism.
What is an idempotency key?
An idempotency key is a client-supplied identifier for one logical operation. When the server receives a retry with the same key and equivalent parameters, it can recognize the operation and avoid performing the side effect twice. The client must keep the key stable across attempts, and the server must retain enough state to recognize it.
The exact replay semantics and retention period belong to the API's contract. A header alone does not grant duplicate protection if the server ignores it.
Why APIs need idempotency keys
The classic failure is an ambiguous timeout. The first request may be in progress or already committed when the connection disappears. A retry with a new identity looks like a new order or charge. A retry with the same identity tells the server to reconcile the attempt against the existing operation.
Brandur Leach's engineering article for Stripe explains the problem from the point of view of building dependable payment APIs. Leach described network failures as unavoidable at sufficient scale, even between well-operated servers, and set out to make API operations predictable despite uncertainty. The Stripe design treats idempotency as part of the API's recovery protocol rather than a convenience left to every client to invent. That experience is the reason the feature belongs in both server behavior and SDK retry policy.

Which HTTP methods need an idempotency key?
HTTP defines GET, HEAD, PUT and DELETE as idempotent in their intended effects, although actual API implementations can add side effects or unusual semantics. POST is not generally idempotent: a repeated request might create another record or take another payment. PATCH depends on the operation. A patch that sets an absolute value behaves differently from one that increments a balance.
Use idempotency keys wherever retrying a write could duplicate an external effect. Also document the lifecycle of the protected operation and what happens while the original request is still running.
The Idempotency-Key header
The IETF HTTP API draft for Idempotency-Key describes a standardized header field and guidance for reuse and error handling. Its proposed structured field representation places the string value in quotes:
POST /orders HTTP/1.1
Host: api.example.test
Content-Type: application/json
Idempotency-Key: "7c9e-ab12-4f51"
{"sku":"book","quantity":1}Some existing APIs accept an unquoted value. Follow the API you are calling, and do not reuse the same key with a different payload.
How Stripe handles idempotency keys
Stripe's idempotent requests documentation describes a concrete implementation for its v1 API. A repeated eligible POST with the same key returns the stored status and body after the first execution begins, including failures such as a 500. Stripe compares parameters, rejects mismatched reuse and documents a retention window after which old keys can be pruned.
That behavior is a useful design reference, but not every provider makes the same choices. In particular, storing a failed response and retrying a still-running operation are decisions you must document explicitly.

Sending an idempotency key
Create one key per logical operation before the retry loop. The SDK should preserve it through a network timeout or a retryable server response. For example:
import uuid
import httpx
key = str(uuid.uuid4())
with httpx.Client(timeout=5) as client:
response = client.post(
'https://api.example.test/orders',
json={'sku': 'book'},
headers={'Idempotency-Key': key},
)If that attempt fails ambiguously, retry with key, not a new UUID. Never put personal data or API keys inside an idempotency key; it is an identifier, not a secret.
Honoring idempotency keys on the server
Store a fingerprint of the request and a durable record of the operation's state. The lookup and reservation must be atomic: two concurrent requests with the same key cannot both pass a naive if not exists check and execute independently. Associate the stored result with a suitable retention policy and reconcile a repeat request that arrives before the first has finished.
For the same key with different parameters, return a clear conflict or validation error. For the same key while work is pending, publish whether the caller should wait, poll or retry.
Common idempotency key mistakes
Generating a new key on each retry is the obvious error. Others include keeping the deduplication map only in one server process, failing to compare request bodies, letting two concurrent requests race, and claiming all writes are safe merely because the SDK adds the header. Also avoid retrying for longer than the key-retention window without checking the resource's actual state.
Idempotency keys in SDKs
An SDK can generate keys automatically for selected write methods, reuse them across retries and expose an override for advanced callers. It should document which operations the server protects and whether a caller-supplied key survives an application restart. Implementing this once avoids the common failure in which different teams use inconsistent retry loops.

Idempotency key checklist
Define the key scope, retention period, parameter comparison and in-flight response. Test two concurrent calls with the same key, a lost response followed by a retry, different payloads under one key and a retry after retention expires. Confirm the SDK sends the same key on every attempt.
Idempotency keys with Octri
Octri's SDK customization can help align a client's write behavior with the API's declared idempotency rules. Validate the server side independently: the client can reuse a key, but only the API can guarantee that one operation is applied once.