🔧 Programmierung 🕛 vor 3 Monaten 4 Min Lesezeit
0

Idempotency Keys: The Simple Trick That Prevents Duplicate Payments and Ghost Orders

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Idempotency Keys: The Simple Trick That Prevents Duplicate Payments and Ghost Orders



You've seen it happen. A user clicks "Place Order," the network hiccups, the request times out, and now they've been charged twice. Or the charge went through but the order never appeared. Neither outcome is acceptable, and both are preventable — with idempotency keys.






What Is an Idempotency Key?



An idempotency key is a unique identifier you attach to a request so that the server can safely process it exactly once, no matter how many times the client retries. If the server receives the same key again, it returns the original response instead of executing the operation a second time.



The concept is borrowed from mathematics: an operation is idempotent if applying it multiple times produces the same result as applying it once. DELETE /users/42 is naturally idempotent — deleting an already-deleted user changes nothing. POST /orders is not — sending it twice creates two orders.



Idempotency keys make non-idempotent operations safe to retry.






How It Works in Practice



The client generates a unique key (typically a UUID v4) before sending the request. It attaches the key as a header, usually Idempotency-Key. The server stores the key and the response in a short-lived cache (24 hours is common). On retry, the server finds the key, skips execution, and returns the stored response.



Here's a payment request using this pattern in Python:




CODE
import uuid
import httpx

def charge_customer(customer_id: str, amount_cents: int) -> dict:
idempotency_key = str(uuid.uuid4()) # generate once, store for retries

headers = {
"Authorization": "Bearer sk_live_...",
"Idempotency-Key": idempotency_key,
"Content-Type": "application/json",
}

payload = {
"customer": customer_id,
"amount": amount_cents,
"currency": "usd",
}

for attempt in range(3):
try:
response = httpx.post(
"https://api.stripe.com/v1/charges",
headers=headers, # same key on every retry
json=payload,
timeout=10,
)
response.raise_for_status()
return response.json()
except (httpx.TimeoutException, httpx.ConnectError):
if attempt == 2:
raise
continue






The critical detail: the idempotency_key is generated once before the loop, not inside it. Every retry sends the identical key, so the server knows they're all the same request.






Implementing the Server Side



If you're building an API that accepts payments, bookings, or any state-changing operation, you need to store and check idempotency keys yourself.




CODE
import { randomUUID } from "crypto";
import { redis } from "./redis";

async function handleCharge(req: Request): Promise<Response> {
const key = req.headers.get("Idempotency-Key");

if (!key) {
return Response.json({ error: "Idempotency-Key header required" }, { status: 400 });
}

// Check for a cached response
const cached = await redis.get(`idem:${key}`);
if (cached) {
return Response.json(JSON.parse(cached), { status: 200 });
}

// Execute the operation
const result = await processCharge(req);

// Store result for 24 hours
await redis.set(`idem:${key}`, JSON.stringify(result), "EX", 86400);

return Response.json(result, { status: 201 });
}






A few implementation notes worth keeping in mind:



Scope keys to the user. Store the key as user:{userId}:idem:{key} to prevent one user from accidentally (or maliciously) colliding with another's key.



Don't cache errors. If the operation fails with a 500, don't store the result — let the client retry with the same key and give the operation another chance. Do cache 4xx errors, since a bad request won't succeed on retry.



Return the same status code. If the original response was 201 Created, the cached response should also be 201, not 200. Clients sometimes branch on status codes.






When to Require Idempotency Keys



Not every endpoint needs them. GET requests are already safe to repeat. Natural idempotent operations (DELETE, PUT with full resource replacement) don't need extra help. But you should require idempotency keys for:




  • Payment and refund creation

  • Order placement

  • Email or SMS sends

  • Any operation that creates a resource or triggers a side effect



Stripe, Braintree, and Adyen all require idempotency keys on charge endpoints for exactly this reason. If you're building a public API, following their lead protects your users and your data integrity.






Testing Idempotency



Before shipping, verify the behaviour explicitly in your test suite:




CODE
def test_duplicate_charge_is_ignored():
key = str(uuid.uuid4())
first = client.post("/charges", headers={"Idempotency-Key": key}, json=payload)
second = client.post("/charges", headers={"Idempotency-Key": key}, json=payload)

assert first.status_code == 201
assert second.status_code == 201
assert first.json()["id"] == second.json()["id"] # same charge, not a new one
assert db.count_charges() == 1 # only one record created









Idempotency keys are one of those small API design choices with an outsized reliability impact. They're cheap to implement and expensive to skip — your support team (and your users) will thank you.



If you want to test idempotency key behaviour against your API without writing scaffolding from scratch, APIKumo lets you set custom headers like Idempotency-Key per-request or as collection-level defaults, so you can replay the same request with identical headers and verify your server handles duplicates correctly. It's a quick sanity check before you ship.

Vollständiger Original-Artikel
Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
6 Quellen
CVE-2022-44255 | TOTOLINK LR350 9.3.5u.6369_B20220309 buffer overflow (EUVD-2022-47204)
2 Quellen
CVE-2026-68426 | Linux Kernel up to 6.18.41/7.1.5/7.2-rc3 xfrm validate_xmit_skb_list use after free (Nessus ID 346426)
1 Quelle
Windows 11 Probleme mit gültiger Domänenanmeldung nach September-Update [Workaround]
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Idempotency Keys: The Simple Trick That Prevents Duplicate Payments and Ghost Orders

Thematisch verwandte Begriffe: Idempotency, Keys, Simple, Trick · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...