Retries without duplicate effects: design idempotency as an API contract
A timeout does not reveal whether the server failed before or after the effect. Safely retrying POST or PATCH requires operation identity, request fingerprint, execution state, a retained result, and an expiry policy.
- Nature
- Architecture guide based on published RFCs, OpenAPI, and an expired Internet-Draft
- Scope
- APIs with material effects and clients subject to timeout/retry
- Published and verified
- 4 August 2026
- Limit
- The contract must fit domain transactions, consistency, and risk

In brief
HTTP defines idempotent methods by intended semantics, but that does not make every implementation or sequence automatically safe. Creation, payment, send, or change operations need domain deduplication. A key should be unique within principal, operation, and resource scope; the server binds it to a normalised payload, atomically wins the right to execute, and stores state and response. An equal replay receives a consistent result; the same key with a different payload is rejected; concurrent requests receive an explicit state. The client retries only documented conditions with backoff, jitter, and a limit.
- HTTP idempotency describes the intended effect of repeated identical requests; it does not replace transactions, deduplication, or reconciliation.
- The key should not be global: include identity/tenant, operation, resource, and content fingerprint.
- Idempotency-Key draft -07 expired on 18 April 2026 and is not an RFC; use it as input, not a published standard.
- Persisting only the key without state and result creates races, inconsistent responses, and duplication after failure.
Idempotent semantics and single execution are different promises
RFC 9110 defines PUT, DELETE, and safe methods as idempotent in terms of the client's intended effect. Logs, metrics, and other secondary effects may repeat. POST and PATCH are not idempotent by definition, but an application can offer retry-tolerant operation by contract.
The Idempotency-Key Internet-Draft contains useful ideas — uniqueness, fingerprint, responsibilities, and errors — but remains expired work in progress. Document behaviour in OpenAPI and do not claim compatibility with a standard that does not exist.
State of a retryable operation
- RECEIVEValidate scope and format
Authenticate, authorise, and validate key, operation, resource, and payload.
- RESERVECreate atomic record
Store composite key and fingerprint as in progress, or read the existing record.
- EXECUTEProduce one effect
Use a transaction/outbox or domain-appropriate reconciliation.
- COMPLETEPersist result
Store status, representation/reference, essential headers, and time.
- REPLAYReturn or reject
Same result for same fingerprint; key conflict for changed content.
- EXPIREApply explicit retention
Reuse only after the contractual window and with replay risks understood.
Specify every state visible to the client
The happy path is easy. Document the response while the first request is running, after completion, after failure before effect, when effect is uncertain, when payload changes under the same key, and after expiry. Use Problem Details for machine-readable errors without exposing sensitive data.
Replay matrix
| Stored state | New request | Response | Client action |
|---|---|---|---|
| Absent | Valid key and payload | Accept and reserve | Await result |
| In progress | Same fingerprint | Conflict/in-progress + retry hint | Bounded backoff |
| Completed | Same fingerprint | Consistent stored result | Do not repeat effect |
| Failed before effect | Same fingerprint | Repeatable error or controlled retry | Follow contract |
| Uncertain result | Same fingerprint | Pending/reconciliation | Query state; do not recreate |
| Any | Different fingerprint | Key conflict | Create new operation |
| Expired | Any | Documented behaviour | Do not assume deduplication |
Test where the network breaks the narrative
Inject failure before reservation, after reservation, before commit, after commit, and before the response. Repeat with two concurrent requests and two server instances. Count effects in the system of record, not only HTTP responses.
Choose retention from the longest retry window, asynchronous latency, reconciliation, and duplicate-operation risk. For payments or irreversible effects, prefer a durable status query and reference over guessing that the operation failed.
- Do not treat the key as a secret or allow it across tenants.
- Apply rate limits without deleting the deduplication record.
- Retain a canonical hash/fingerprint without unnecessary sensitive payload.
- Monitor replays, conflicts, stuck operations, expiries, and reconciliations.
Sources consulted
Consulted on the stated update date.
Opens in a new window.- 01RFC 9110 — HTTP SemanticsIETF · SYS-IETF
- 02Idempotency-Key HTTP Header Field — Internet-Draft -07IETF HTTPAPI Working Group · SYS-IETF
- 03RFC 9457 — Problem Details for HTTP APIsIETF · SYS-IETF
- 04OpenAPI Specification 3.1.0OpenAPI Initiative · SYS-OPENAPI
- 05RFC 6585 — Additional HTTP Status CodesIETF · SYS-IETF
- 06RFC 9111 — HTTP CachingIETF · SYS-IETF
Participate
Share the analysis. Add context.
Distribute the article through your channel or leave an observation connected to the topic.

Comments
Loading the conversation.