Idempotent APIs: Design, Keys and Versioning

Engineer rerunning an API request at workstation

For a separate example outside the enterprise integration context, An idempotent API is one where repeating the same request leaves the system in the same state as sending it once. The response may differ, but the effect must not. That property is what lets a client retry after a timeout without charging a customer twice, creating a duplicate order or shipping a parcel again. This guide covers which HTTP methods are idempotent, how idempotency keys make POST safe to retry, what to do with concurrent and late requests, and how API versioning keeps all of this stable as your estate evolves.

Polarising
Make Complex Integrations More Reliable
Polarising builds AI systems integrated into business processes, with governance and accountability designed in from the outset.

Explore AI integration

Key takeaways

  • Idempotency is about the effect on server state, not about returning an identical response every time.
  • GET, HEAD, OPTIONS, TRACE, PUT and DELETE are idempotent by specification. POST is not, and needs an idempotency key to be retried safely.
  • A good key scheme has four rules: unique keys, stored results, rejection of a reused key with a different payload, and a clear answer for concurrent duplicates.
  • Versioning and idempotency are linked: a breaking change to how keys or retries behave is a breaking change, and consumers need time to migrate.
  • In enterprise integration, idempotency has to hold across gateways, queues and legacy systems, not just in one service.

Table of Contents

What idempotent really means

The HTTP specification defines an idempotent method as one where the intended effect of several identical requests is the same as the effect of one, even if the response status codes differ. The classic example is deleting a resource. The first DELETE returns a success code. The second may return a not-found code. The responses differ, yet the server ends in the same state: the resource is gone.

This matters because many teams confuse idempotency with determinism. An idempotent API does not have to return the same body for the same input. A create-or-return endpoint might return 201 the first time and 200 afterwards. What it must not do is create a second record.

It is also worth knowing that the specification encourages servers to follow idempotent semantics but does not mandate them. A method labelled PUT that appends a row on every call is a bug in your implementation, and no standard will stop it reaching production.

Which HTTP methods are idempotent

Per RFC 9110 as summarised here, GET, HEAD, OPTIONS, TRACE, PUT and DELETE are idempotent. POST and CONNECT are not. PATCH is not idempotent by default, though a server can design it to be.

Method Safe Idempotent Typical risk on retry
GET, HEAD, OPTIONS Yes Yes None to server state
PUT No Yes Overwrites with the same data, so low
DELETE No Yes Second call may return not found
PATCH No Only by design Relative changes (“add 10”) apply twice
POST No No Duplicate resources, duplicate payments

Safe versus idempotent

Safe methods are a stricter group. They have read-only semantics: the client is not asking for a change, although servers may still log requests or keep statistics. Every safe method is idempotent, but PUT and DELETE are idempotent without being safe. The distinction decides what browsers, crawlers and gateways may do automatically, and it should decide what your client libraries retry without asking.

Why retries make idempotency non-negotiable

In a distributed system, a client that times out does not know whether the server processed the request. Either the request never arrived, or it was processed and the reply was lost. A client needs a documented recovery strategy: reconcile the outcome, or retry when the operation provides reliable duplicate protection.

AWS describes the underlying trade-off in its reliability guidance: at-least-once delivery is comparatively simple, while exactly-once behaviour is harder and can rely on idempotency tokens. In practice, most enterprise messaging is at-least-once. Consumers should be designed on the assumption that duplicates may arrive. The question is whether they are harmless.

Idempotency keys: making POST safe to retry

An idempotency key is a unique value the client generates and sends with a non-idempotent request. The server associates the key with the logical operation and its outcome. A subsequent request with the same key can be recognised and handled without repeating the business effect, according to the endpoint’s documented contract.

The IETF is developing a specification for this. The IETF’s Idempotency-Key header draft describes a request header that lets clients make POST or PATCH fault-tolerant by supplying a unique identifier. It recommends UUIDs or comparable random identifiers. The latest draft available on 27 October 2026 is draft-08, published on 22 October 2026; it is not yet a final RFC.

Idempotency keys: making POST safe to retry — overview diagramprediction market data APIs.

The rules that make a key scheme trustworthy

  1. Unique, client-generated keys. Use a UUID per logical operation, not per attempt. A retry reuses the key. A new business action gets a new one.
  2. Reject payload mismatch. The draft specifies against reusing a key with a different request payload. Store a fingerprint of the request, such as a SHA-256 hash of the body, and compare it on every repeat. Open-source middleware such as hono-idempotency takes this approach.
  3. Handle completed requests consistently. Replaying the original status code and response body is a useful and predictable design, but the draft requires a response consistent with the operation having completed, not necessarily byte-for-byte identical output.
  4. Handle the in-flight case. If a duplicate arrives while the first request is still running, the draft’s answer is a resource-conflict error. A 409 Conflict is the usual choice, and the client waits and retries.
  5. Expire keys deliberately. Keys cannot live forever. Pick a retention window longer than your longest realistic client retry, document it, and test what happens after it ends.

Where the key check must sit

The deduplication decision and the local business-state change must be coordinated atomically wherever possible. A common failure is to look up the key, find nothing, perform the work, then write the key. Two concurrent requests both find nothing and both do the work. Reserve the key with a unique constraint and commit its outcome with the local business change in one transaction where possible. For externally executed effects, use durable orchestration, reconciliation or a downstream idempotency facility rather than assuming a local transaction can cover both systems. Where the side effect lives in another system, such as a core banking platform or a carrier’s booking engine, pass the key downstream so that system can deduplicate too.

Concurrent duplicate requests and atomic key handling

Late and conflicting requests

AWS also discusses the awkward cases in its note on making retries safe: requests that arrive late, and requests that reuse a client request ID with a different intent. These are the cases that cause incidents.

A practical policy:

  • Repeat after completion: return the original result.
  • Repeat during processing: return a conflict and let the client back off.
  • Same key, different body: reject with a client error. Never silently pick one.
  • Late arrival after a cancel or timeout: decide explicitly whether the late request may still succeed, and record that decision in the API contract.

Designing and testing for idempotency

Document which operations accept retries. Microsoft’s API implementation guidance recommends this, along with middleware that stores response status codes and bodies and checks consistency between key and body.

A test plan for an idempotent endpoint should cover at least:

  • the same request sent twice in sequence;
  • the same request sent twice in parallel;
  • a network failure after the server commits but before the client receives the reply;
  • a key reused with a different payload;
  • a request after the key has expired and been cleaned up.

Run these against the deployed path, including the gateway and any queue, not only against the service in isolation. Duplicates are often introduced by the infrastructure in front of your code.

Idempotency across an integration estate

Within one service, a unique database constraint is often central to implementing idempotency. In an enterprise, it is a property of a chain: client, gateway, integration platform, message broker, back-end system. Each hop may retry. A guarantee that holds at one hop and not the next is no guarantee.

Three patterns help in practice:

  • Propagate a stable operation identifier end to end. A stable business-operation identifier can travel through headers and message metadata; each component must define the scope and lifetime of its deduplication state.
  • Make consumers idempotent, not just producers. If the broker offers at-least-once delivery, the consumer must tolerate repeats. This is the usual design in event-driven architectures.
  • Deduplicate at the system of record. Some legacy platforms lack native support for idempotency keys. A durable adapter may provide deduplication, although it cannot always eliminate duplicate effects if the downstream commit outcome is unknown; and a natural step in legacy modernisation.

This applies whichever integration platform sits in the middle. API management and iPaaS tools such as Boomi and MuleSoft, enterprise messaging such as TIBCO and Solace, all let you set retry policies and route messages. None can make a back-end operation safe to repeat on its own. That is a design decision in the flows and services you build on top, and it requires explicit design across the end-to-end workflow. Our integration platforms and technologies page sets out the tooling we engineer with.

API versioning: keeping integrations stable as contracts change

Idempotency promises are part of your API contract, so they are subject to versioning. Changing key retention, altering which status code a replay returns, or tightening payload validation can break clients that retry. Versioning is how you change the contract without breaking them.

When to introduce a new version

The rule from Microsoft’s guidance is simple: when you introduce a breaking change, provide a new version and keep supported earlier versions available in parallel for a period, so existing consumers can migrate. Adding an optional field is not breaking. Removing a field, changing its meaning, or changing retry behaviour is.

A useful discipline is semantic numbering. The OAGi’s RESTful Web API design guidance uses major.minor.patch: a patch for a bug fix, a minor version that stays backward compatible, and a major version that breaks compatibility.

Avoid versioning where you can

The Zalando API guidelines tell designers to avoid versioning by using compatible extensions, such as adding only optional fields and never changing field semantics. The Swiss Federal Administration’s API guidelines also recommend compatible extensions.

URL or media type versioning

When a break is unavoidable, there are two main routes.

Approach Example Strength Weakness
URL versioning /v1/customers Visible, easy to route and cache Couples the identifier to the version
Media type versioning application/x.type+json;version=2 Less coupling, the resource stays the same Harder to see, test and debug

The Swiss guidelines recommend URL versioning, while Zalando prefers media type versioning to reduce coupling. Both are defensible. Microsoft’s advice is that whichever you choose, apply it consistently across the application and API gateways so caches and routers can tell versions apart. For most enterprise estates with several gateways and teams, consistency matters more than the choice.

A practical versioning policy

  1. Default to compatible extensions.
  2. Version only on a genuine break, and say what counts as one in writing.
  3. Run old and new versions in parallel with a published retirement window.
  4. Keep idempotency behaviour identical across versions unless the change is announced as breaking.
  5. Monitor which consumers still call old versions before you switch anything off.

Governance is what makes this stick. We have written about API governance without blocking delivery in legacy-heavy estates, and the same principle applies here: standards that teams can follow without waiting for a committee.

Our perspective

Duplicate-processing incidents in enterprise estates are often not caused simply by a missing header. They happen at the seams: a gateway that retries, a queue that redelivers, a legacy system with no notion of a request identity. Teams fix the API and leave the chain exposed.

Our view is that idempotency should be designed in from the start, with governance and accountability, rather than patched after the first double payment. That means a single business identifier across hops, consumers that tolerate repeats, a contract that states the retry behaviour, and tests that exercise the real path. It also means treating that behaviour as versioned, because clients depend on it.

With senior nearshore engineering teams in the UK and Portugal, Polarising works on enterprise integration and modernisation in environments where existing platforms cannot simply be replaced overnight. A carefully designed adapter can be more realistic than treating every system as a greenfield build. Our work with TAP Air Portugal is an example of integration work in that kind of environment.

— Polarising Team

Getting help with idempotent integration design

If you are reviewing retries, duplicates and API contracts across a complex estate, our Enterprise Integration Services cover API and event platform integration, legacy modernisation and migration, delivered by senior teams. We can assess where duplicates can enter your chain and engineer the fix with you.

FAQ

What is an idempotent API?

It is an API where repeating the same request has the same effect on server state as making it once. The response can differ between calls, for example a success first and a not-found afterwards. What matters is that the intended change happens only once.

Is POST idempotent?

No. POST is not idempotent by specification, so a retry can create a duplicate. You make it safe to retry by adding an idempotency key that the server stores and checks, as described in the IETF draft.

What should happen if two requests with the same idempotency key arrive at once?

The second should not repeat the work. The IETF draft’s answer for a concurrent retry is a resource-conflict error, commonly 409 Conflict. Once the first request completes, later retries receive its stored result.

Do I need to version my API to add idempotency keys?

Usually not. Accepting an optional header is a compatible extension, and clients that do not send it are unaffected. Making the key mandatory on an existing endpoint is a breaking change and should go in a new version.

Sources