Skip to content
API Design Learn/Production REST II: Correctness & Scale
Browsing as a guest. Sign in to save your progress and earn XP as you complete chapters.

Idempotency Keys

7 min read

You'll learn to

  • -Implement idempotency keys so a retried POST request never double-processes (e.g. double-charges) an operation
  • -Explain why POST needs an explicit idempotency mechanism when PUT and DELETE are already naturally idempotent

GET, PUT, and DELETE are naturally idempotent by the HTTP spec's own definition - but POST, used for creating resources and triggering actions, is explicitly not, which becomes a real production problem the moment a network timeout happens: the client never received a response, but the request may well have already succeeded on the server. Does the client retry, and risk creating the resource (or charging the payment) twice?

The Idempotency-Key Header

A client-generated key makes an unsafe POST retry-safe
POST /payments
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
{"amount": 4999, "currency": "usd", "customer_id": 42}

HTTP/1.1 201 Created
{"id": "pay_501", "status": "succeeded"}

# The exact same request, retried after a timeout - same key, same body:
POST /payments
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
{"amount": 4999, "currency": "usd", "customer_id": 42}

# Server recognizes the key was already processed - returns the ORIGINAL
# result again, without charging a second time:
HTTP/1.1 201 Created
{"id": "pay_501", "status": "succeeded"}

The client generates a unique key (typically a UUID) once per logical operation, before the first attempt, and sends the same key on every retry of that same operation. The server stores a mapping from idempotency key to the result it already produced - a retried request with a seen key returns the stored result directly, without re-executing the underlying action.

What Happens on a Body Mismatch

The same key, but a genuinely different request body - a real conflict
POST /payments
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
{"amount": 9999, "currency": "usd", "customer_id": 42}

HTTP/1.1 409 Conflict
{"error": "Idempotency-Key already used with a different request body"}

If the same key shows up with a genuinely different body, that is not a legitimate retry - it is either a client bug (accidentally reusing a key) or an attempt to piggyback a different operation on an already-consumed key. Returning 409 rather than silently processing the new body (or silently returning the old result) surfaces the mismatch instead of hiding a real bug.

A Reasonable Retention Window, Not Forever

Idempotency keys don't need to be stored indefinitely - a retry that matters happens within seconds to minutes of the original attempt, not months later. A bounded retention window (commonly 24 hours) is enough to cover realistic retry scenarios without the storage cost of an ever-growing key table.

This is the exact same idempotency-key pattern covered for financial ledgers in LLD Fundamentals' money-modeling chapter - here it's the API-facing half of the same underlying problem: preventing a network-level retry from becoming a duplicate business operation.

Interview Signal is part of Pro

See a real weak answer next to a real strong one for this exact topic.

Quiz is part of Pro

Test what you just read with a short quiz, and bank the XP.

Ready to Build This?

Design Idempotency Shield in the API Design Lab's Production Patterns act.

ScaleDojo Logo
Initializing ScaleDojo