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 running, and which failures are worth remembering. Skip those and you've made double charges rarer without making them impossible, which is the worst outcome available: now nobody is watching for them.

The promise is "same outcome", not "skip the duplicate"

HTTP already has idempotent methods. RFC 9110 defines PUT and DELETE that way: sending the request twice leaves the server in the same state as sending it once. POST is deliberately excluded, which is why the header exists at all. It's a way to bolt the property onto the one method that doesn't have it.

Notice what the definition covers and what it doesn't. It constrains server state. It says nothing about what the caller sees, and the caller is the entire reason you're doing this. Here's the handler people write first: