← Engineering decisions

How do you stop a payment being processed twice?

An idempotency key enforced by a uniqueness constraint at the point of record, not a check-then-act in application code.


“Check if it exists, then insert” is a race with itself. Under concurrency, two requests both check, both find nothing, and both insert.

The version that holds is a natural or derived idempotency key with a unique constraint in the database. The second write does not need to be prevented — it needs to fail, and be recognised as a duplicate rather than an error. The constraint violation is the signal.

Two consequences worth stating plainly:

  • Retries become safe. A caller that does not know whether its request landed can send it again. That is the whole point.
  • Reversal and dispute paths need the same treatment. They converge on the same records, so they need keys of their own or they reintroduce the problem through a side door.

Related work and writing

Case studyPayment Distribution Engine30–40 min → 6–8 min per cycleCase studyFedNow ISO-20022 Message Handling3,000+ parameters, specified and validatedJournalWhen Parallel Streams Become a Production ProblemparallelStream() is one call away and looks like free concurrency. On I/O-bound work sharing a JVM-wide pool, it is a way to make unrelated code slow.
Next decisionHow do you query a billion-row transaction table without falling over?