Ensuring Idempotency
1. Understanding Idempotent Operations
Method Idempotent Why
GET, HEAD, OPTIONS Yes No state change
PUT Yes Same body → same final state
DELETE Yes State after = absent
POST No (default) Creates new each time
PATCH Depends Merge yes; relative ops no
2. Implementing Idempotent POST Requests
Technique How
Idempotency-Key header Server stores key+response; replay returns cached
Client-supplied UUID in body Reject duplicates by ID constraint
Natural unique key Use email, SKU as deduplicator
Stripe-popularized convention; now a draft IETF RFC.
Example: Idempotency-Key
POST /payments HTTP/1.1
Idempotency-Key: 7f2e1a4b-9c3d-4e5f-8a1b-2c3d4e5f6a7b
Content-Type: application/json
{ "amount" : 100, "currency": "USD"}
# First call: 201 Created (charge processed)
# Retry same key: 201 Created (cached response, NO duplicate charge)
4. Storing Idempotency Keys
Storage Stored Fields
Key Idempotency key (string)
Request fingerprint Hash of method+path+body
Response Status, headers, body
Created/expires Timestamps
Lock state To handle concurrent retries
5. Handling Duplicate Requests
Scenario Server Response
Same key, same payload Return cached response
Same key, different payload 422 (key reused for different request)
Same key, in-flight Wait or 409 Conflict
6. Returning Cached Responses
Header to Echo Purpose
Original status code Same as first call
Idempotent-Replayed: trueIndicates cached reply
Original body bytes Byte-for-byte identical preferred
7. Implementing Idempotency for Payments
Practice Reason
Mandatory Idempotency-Key Prevent double charges on retry
UUID v4 / ULID Unique, unguessable
Per-user key namespace Avoid cross-user collisions
Persist 24h+ Cover long retry windows
8. Handling Idempotency Key Expiration
TTL Use Case
24 hours Stripe default
7 days Long-running batch jobs
After expiration Same key allowed for new request
Rule Reason
Min 16 chars, max 255 Prevent short collisions / abuse
UUID/ULID recommended Sufficient entropy
Reject empty/whitespace Avoid accidental disabling
10. Documenting Idempotency Behavior
Doc Field Content
Endpoints supporting key List explicitly
Key format UUID, length
TTL Storage duration
Conflict behavior 422 on payload mismatch