The payment succeeded. The response never arrived.
Now the client doesn't know. It retries — correctly, by its own logic. The customer is charged twice.
The network can lose the answer without losing the action. Your API has no idea these are the same request.
Unless you give it one: an idempotency key. The client generates a unique ID and sends it with the request. The server stores it with the result.
| Request | What the server does |
|---|---|
| First time | Do the work, save the result against the key |
| Again, same key | Key exists — return the saved result, do nothing |
Same key, same answer, no second charge.
The key must come from the client, and must survive its retries — generate it once, before the first attempt, not inside the retry loop.
