Summary

  • The expired HTTPAPI Idempotency-Key draft puts key lifecycle and published expiry policy in the resource contract. Actual services also impose retention boundaries: Stripe documents new processing after a pruned key is reused, while AWS describes service-specific handling of late requests.
  • Deduplication memory and authority to produce an effect need separate lifetimes. After the retry window, an unresolved operation should be reconciled against a durable operation identity or held for review—not silently treated as a new instruction because the server no longer remembers its token.

Consider a worker that sends an instruction, loses the reply and then goes offline. The server may have completed the work. The client only knows that it did not receive confirmation. When the worker returns, it resubmits the same request with the same idempotency key. If the server still retains the original entry, the retry can be recognised. If that entry has been purged, the same token may now accompany what looks like a first request.

No new intent has necessarily appeared. Only one side’s memory has changed.

That is the boundary concealed by a comforting phrase such as “safe retries.” The assurance depends on the service, the operation, the identity scope, the payload comparison and the lifetime of retained state. It does not arise from the header’s presence alone. A random string can identify a request; it cannot prove that a business effect never occurred, or authorise repeating it after the record used for deduplication disappears.

draft-ietf-httpapi-idempotency-key-header-07 provides a useful description of the contract. Published on 15 October 2025, it proposes an Idempotency-Key structured header whose value is a string, a uniqueness rule, an optional payload fingerprint and treatment of completed and concurrent duplicates. The resource owns the key lifecycle and should publish applicable expiration rules.

The document’s status is important. Revision 07 expired on 18 April 2026. At this article’s research cutoff it is an expired, archived HTTPAPI Working Group Internet-Draft, not an active draft, RFC or approved standard. Working Group provenance is not the same as consensus approval. The analysis below uses its proposed semantics alongside current service documentation; it does not promote them into universal HTTP obligations.

The timeout leaves an epistemic problem

HTTP method idempotence concerns the intended effect of repeating a method, as RFC 9110 explains. It does not mean every attempt produces identical logs or responses. Nor does it turn an arbitrary POST or PATCH into an end-to-end exactly-once operation. A resource may define an idempotent contract for such an operation, but the client must know that contract.

The draft makes this limit explicit: a generic client can supply a key to express an intention to perform an action once, yet cannot assume that an arbitrary server respects it. The server’s documentation must define what is recognised as the same request, how long recognition lasts and how conflicts are reported.

Even within that contract, a lost response is not evidence of non-execution. The request may have failed before acceptance, remained in progress, completed successfully, or committed a side effect before another component failed. Those states require different actions. Retrying because the client lacks a reply is reasonable only where the service can resolve that uncertainty without issuing an unintended second effect.

The proposed treatment of duplicates illustrates the difference. A retry after completion receives the earlier result, whether success or error. A retry while the original is still processing receives a conflict. A reused key with a different payload receives a different failure. These are distinctions about operation state and identity, not interchangeable reasons to generate a fresh key and try again.

A retention policy is part of the safety promise

Key storage cannot simply be assumed infinite. A service must balance memory, lookup cost, collision scope, data retention and the late-arrival patterns it intends to support. The question is not whether it may purge state, but whether callers can identify the consequence of that purge before they act.

Stripe’s current official documentation offers a concrete boundary. It saves the first status code and body for a key once endpoint execution begins, including error results. Validation failure or a concurrency conflict before execution does not create that saved result. Keys may be removed once they are at least 24 hours old; reusing a key after its original entry has been pruned generates a new request. This is a service-specific rule, not a promise that every key expires at exactly 24 hours, and not evidence that any particular customer suffered a duplicate effect.

AWS’s Builders Library describes another approach through its EC2 example. Late retries can arrive after another actor has deleted the resource. The service can preserve a semantically equivalent response rather than recreate the resource. Retaining knowledge of the initial request is necessary; the account describes a period linked to resource lifetime plus an interval for late arrivals, while noting that requirements vary across services and resources.

The examples should not be collapsed into one universal TTL. They show why the retention boundary belongs to the operation contract. A queue that may resume after several days, a disconnected device, a disaster-recovery replay and an ordinary short network retry do not share the same delay distribution. A published cache lifetime shorter than a caller’s recovery horizon creates a reconciliation problem that exponential backoff cannot solve.

Keep four identities separate

The first identity is the deduplication token: the value used to recognise retries within the service’s documented scope. The second is the business operation: the intended instruction or decision that should produce a bounded result. The third is the effect or resource actually created. The fourth is a new intention to produce another effect.

Confusing these identities makes expiry dangerous. A new token does not necessarily mean a new business instruction. The same token after purge does not necessarily mean the old instruction failed. A resource’s deletion does not necessarily mean its original creation never happened. And a payload that happens to match a previous one does not always prove identical intent; a user may genuinely wish to perform the same action again.

A durable operation identity can help connect these facts without preserving the entire retry response forever. The record may identify the authorised instruction, caller scope, payload commitment, acceptance time, terminal state, effect reference and reconciliation path. It should be compact, access-controlled and retained for a justified period. Sensitive payloads need not be copied into a permanent ledger merely to preserve deduplication.

This record is an architectural recommendation, not a new Idempotency-Key field mandated by the draft. Different services may realise the outcome differently. The invariant is narrower: after ordinary retry memory ends, there must still be a defensible way to decide whether an old unresolved instruction can act again.

Define what happens outside the window

An expiry policy should describe more than when storage is deleted. It should say which time starts the window, which caller and operation scope it covers, whether completed errors are remembered, how in-progress work is treated, and what a late request can expect. The client needs a retry deadline and a terminal-state lookup or reconciliation procedure.

Beyond the deadline, an ambiguous retry should not automatically become fresh execution. A service can reject it, place it in a reviewable state, or resolve it against the durable operation record. A client can stop automatic delivery, query the known operation or resource, and escalate uncertainty. Where a genuinely new effect is wanted, fresh intent should be explicit and separable from the old recovery attempt.

That does not require every service to keep every key forever. It requires a boundary between forgetting a token and granting authority. A documented policy can make clear that the ordinary deduplication contract has ended and that further action needs another form of evidence. If a service intentionally treats post-pruning reuse as new processing, the client workflow must not pretend that the old safety promise continues.

The boundary also belongs in automation. SDK retries, job queues, disaster-recovery tooling and human support interfaces can each resend the same logical instruction. Their maximum delay should be compared with the service window. An operator clicking “retry” after a long outage may be activating a different contract from the one used by the SDK seconds after a timeout. The interface should make that difference visible.

The record and the effect must agree

The most serious failure is not a repeated packet. It is disagreement between recorded identity and committed consequence. A service that remembers a token but fails to create the resource can report a false completion. A service that creates the resource but fails to remember the token can repeat the effect. AWS’s account emphasises that recording the token and the mutations must be coordinated as an all-or-nothing operation.

Across multiple systems, however, one local atomic transaction may not cover every downstream effect. A server can commit its own row while a later instruction succeeds elsewhere and the acknowledgement disappears. A receipt that describes only the first database cannot establish the final state of the chain. The reconciliation design must identify the system authoritative for each effect and the evidence used to distinguish completed, pending, failed and unknown states.

Testing should therefore include delayed retries after normal cache expiry, retries after resource deletion, changed payloads, caller-scope changes and partial downstream completion. The expected outcome is not merely a chosen status code. It is the absence of an unauthorised second effect, together with a truthful explanation of the state that remains uncertain.

Do not use an observed quiet period as the only acceptance test. The dormant queue that caused no problem during rollout may return after the retention window. A backup restored from before completion may rediscover an old instruction. A support export can revive a request that the main system has already reconciled. Those are ordinary recovery paths, not exotic attacks.

Sources

  1. Current expired HTTPAPI draft record
  2. Draft history
  3. Revision 07 in HTML
  4. Revision 07 in text
  5. Revision 07 source XML
  6. HTTPAPI charter
  7. HTTPAPI documents
  8. Official draft source repository
  9. Official draft issue tracker
  10. RFC 9110: HTTP Semantics
  11. RFC 9457: Problem Details for HTTP APIs
  12. RFC 8941: Structured Field Values for HTTP
  13. RFC 9562: Universally Unique IDentifiers
  14. RFC 9111: HTTP Caching
  15. Stripe: Idempotent requests
  16. Stripe: Low-level error handling
  17. AWS: Making retries safe with idempotent APIs
  18. AWS: Timeouts, retries and backoff with jitter
  19. Lu Heng: Minimum Initial Specification, Localized Future Decision
  20. Lu Heng: The Policy Mirror