SC
Distributed Systems

Idempotency Patterns

Making operations safe to retry — the single most important property in a payments or integration system. A retried payment must never become a double charge.

Anything that talks to a network will be retried. Brokers redeliver. Clients time out and try again. Incidents get replayed.

Idempotency is the property that doing an operation more than once has the same effect as doing it once. In payments, this is not a nice-to-have. Without it, a retry becomes a double charge.

You cannot eliminate duplicates. You design so they are harmless.

Where duplicates come from

  • At-least-once delivery from a broker.
  • A client retrying after a timeout where the request actually succeeded.
  • Replays during incident recovery.
  • The same file or statement ingested twice.

Idempotency keys

The workhorse. The caller supplies a unique key per logical operation.

POST /payments
Idempotency-Key: 9f1c2e7a-3b...

The server records the key with its result the first time it succeeds. A retry with the same key returns the stored result instead of executing again.

INSERT INTO idempotency (key, response)
VALUES ($1, $2)
ON CONFLICT (key) DO NOTHING;

If the insert conflicts, the work already ran. Return the stored response.

Prefer naturally idempotent operations

Sometimes you can avoid keys entirely.

SET balance = 100 is idempotent. ADD 100 to balance is not.

"Mark invoice X reconciled" is idempotent. "Increment the reconciled count" is not.

At integration boundaries, prefer absolute, declarative operations over relative ones.

Idempotency in money movement

In a payments flow, the idempotency key has to cover the whole logical charge — not just the HTTP call. A user double-clicking, a retried webhook, and a replayed queue message must all collapse to the same single charge.

In a reconciliation engine, the same bank line may arrive many times. Key matches on a deterministic hash of (account, value_date, amount, reference) and re-ingestion becomes a no-op instead of a phantom transaction.

Lesson. Idempotency is a design property, not a library you add later. Decide what "the same operation" means for every external write before you ship it, because retries are not optional — they are guaranteed.

Checklist

  • Every external write carries an idempotency key or is naturally idempotent.
  • Keys are stored durably and survive a restart.
  • The stored result — not just the key — is returned on replay.
  • Keys have a sensible retention window.