The rule that matters
Generate the key when the cashier confirms the amount, hold it for the whole attempt, and throw it away only when you get a final answer.What a repeat returns
201 — same transaction
The repeat matched the original in every respect. You get the original transaction back,
with the same
id. The customer was charged once.409 — conflict
The key was reused for a different charge, or the original has since been reversed. Nothing
was charged. Use a fresh key for a genuinely new sale.
201, your success path needs no special handling at all — the
retry simply succeeds. That is the point.
Choosing keys
Since keys are scoped to your merchant rather than to a terminal, a bare sequential counter per
till will eventually collide with the till next to it. Prefix it, or use a UUID.
Never send a blank key
400 Bad Request
What is protecting the customer
Three independent mechanisms, so a gap in one is covered by another:1
The idempotency key
Collapses your retries into one transaction.
2
The single-use QR code
Even with no key at all, a scanned code cannot be charged twice — the second attempt is a
409.3
Replay resolution
A retry that arrives after the original committed is recognised as a repeat rather than
reported as a spurious decline, even though the balance and the code have both moved on.

