Skip to main content
  1. References/
  2. Architecture Design Basics/
  3. Pattern Taxonomy/
  4. Fundamental Concepts/

Idempotency

·· 211 words· 1 min

πŸ”΄ P0 — critical for payment systems, Stripe’s public API design is built on this

Problem #

In distributed systems, messages can be delivered more than once. Network retries, client timeouts, queue redelivery — all produce duplicates. Without idempotency, a retried payment request charges the customer twice.

Mechanism #

An operation is idempotent if applying it multiple times produces the same result as applying it once.

Naturally idempotent:     GET /user/123          β†’ same result every time
                          PUT /user/123 {name: "R"}  β†’ overwrites to same state
                          DELETE /user/123       β†’ deleted stays deleted

NOT naturally idempotent: POST /charges {amount: 50}  β†’ creates a NEW charge each time
                          counter++                   β†’ increments every call

Making non-idempotent operations safe #

The standard mechanism is an idempotency key: a client-generated unique identifier attached to the request.

Client β†’ POST /v1/charges
         Idempotency-Key: "abc-123"
         {amount: 5000, currency: "usd"}

Server:
  1. Check: have I seen key "abc-123" before?
  2. If yes β†’ return the stored result (don't re-execute)
  3. If no β†’ execute, store result keyed by "abc-123", return result

See also: Idempotency Keys for implementation details.

Key Trade-offs #

DimensionTrade-off
StorageMust store key β†’ result mappings; need TTL / eviction policy
AtomicityCheck-and-execute must be atomic (else race conditions on retries)
Key generationClient-generated (Stripe model) vs server-generated (less flexible)
ScopePer-endpoint? Per-resource? Global? Wider scope = more storage

Instinct #

Every mutating API endpoint in a distributed system should be idempotent. The question is never whether but how. For payments specifically, idempotency isn’t a nice-to-have — it’s a correctness requirement.

References #

DDIA 2e Reference #

  • Chapter 8: Exactly-once semantics, duplicate suppression
  • Chapter 11: Stream processing and deduplication
  • Chapter 12: End-to-end argument for duplicate suppression