Idempotency in payment APIs
A client sends a payment request and the connection drops before the response arrives. It cannot know whether the charge happened. If it retries, a naive API charges twice. Idempotency keys exist to make that retry safe.
The idea
The client generates a unique key per intended payment and sends it with the request. The server stores the key with the result of the first attempt. A second request with the same key returns the stored result instead of doing the work again.
What makes it hard
- Scope. A key belongs to one merchant and one operation. Keys from different merchants must never collide.
- Concurrency. Two requests with the same key can arrive at once. The first to claim the key wins, and the second waits or gets a conflict. A unique constraint is more reliable than a check followed by an insert.
- Same key, different body. Reject it. Reusing a key for a different amount is a bug on the client, and silently accepting it hides the bug.
- Expiry. Keys cannot live forever. Pick a window longer than any sensible retry and document it.
What to return on a replay
The same status code and body as the first response, plus a header that says it was a replay. A client should not be able to tell a replay from the original except by that header.