Idempotency is not a key, it's a contract
Every payments API has an Idempotency-Key header. Far fewer have written down what it means, and the ones that haven't are usually running a SELECT … WHERE key = ? before the insert and calling the job done. A key is a token. A contract is a set of answers: what counts as the same request, how long the answer stays valid, what a caller gets when their retry lands while the first attempt is still…
Idempotency is a crucial concept in payments APIs, but it is often misunderstood. An Idempotency-Key header is required by many APIs, yet few developers understand its true purpose. Rather than simply checking if a key already exists in a database, a proper implementation requires a more nuanced approach.
Idempotency is not about preventing duplicate charges, but rather about ensuring that the same outcome is achieved regardless of how many times a request is made. It is a contract between the client and the server, outlining how responses should be handled when retries occur. The key is a token chosen by the client, while the identity of the request includes both the key and the request body. By storing a fingerprint of the request alongside the key, duplicate requests can be accurately identified and handled.
A consistent approach to hashing request fields is essential to avoid false rejections due to ordering or timestamp differences. It is also important to recognize that the client is the primary focus, as they are the ones retrying failed requests. The server should return the original response, intact, when a retry occurs. This ensures that the client receives the same result as the initial request.
The solution to handling retries lies in letting the database arbitrate, by inserting the key first and checking the result. If the key is successfully inserted, the work proceeds; otherwise, an appropriate response is returned. Implementing this approach prevents double charges, maintains the same outcome for both successful and failed attempts, and allows clients to safely retry failed requests.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.