What idempotency means
An operation is idempotent when its result does not change with the number of times it runs. The standard example: assigning a value to a variable (x = 5) is idempotent — run it a hundred times and the result is the same. An increment (x += 1) is not.
In APIs and distributed systems, idempotency is the guarantee that makes a retry after a failure safe:
# An idempotent request - PUT
PUT /cart/items/SKU-1234
{ "quantity": 2 }
-> A repeat gives the same result: quantity = 2
# A non-idempotent request - POST
POST /cart/items
{ "sku": "SKU-1234", "quantity": 2 }
-> A repeat creates a second line: quantity = 4
Why it matters in e-commerce
In an online store every request travels a chain: browser to CDN to API gateway to backend to database. That chain produces timeouts, dropped connections and repeat requests. Without idempotency:
- Duplicate orders: the shopper pressed Buy, the response never arrived, the browser repeated the request — and a second order was created.
- Double charges: the payment gateway received a retry and processed the transaction twice.
- Distorted analytics: a
purchaseoradd_to_cartevent was counted several times.
The idempotency key in practice
The standard pattern: the client generates a UUID for each operation and passes it in a header.
POST /orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
{ "cart_id": "abc123", "payment_method": "card_xxx" }
The server stores (idempotency_key -> response) with a TTL, usually 24 to 48 hours. On a repeat request with the same key it returns the cached response without running the operation again.
Important: the idempotency key TTL must be long enough to cover the typical retry window — usually a few minutes. But not forever, or the store grows without bound.
Idempotency in personalization platforms
For recommender systems and A/B testing two aspects matter:
| Scenario | Risk without idempotency | Fix |
|---|---|---|
Event API (view, purchase) |
Duplication inflates the product’s weight in the profile | Deduplicate by event_id within a time window |
| Conversion event in an A/B test | One transaction counted twice in the metric | A unique constraint on (test_id, user_id, order_id) |
| User profile update | Surplus data distorts segmentation | PUT instead of POST for updates |
Common integration mistakes
- Using POST instead of PUT to update entities — that makes the operation non-idempotent by design
- Not passing an idempotency key on payment operations
- Handling retries in client code with no deduplication on the server
- Leaving
event_idout of the tracking event schema — adding it later without a migration is hard