• Olatunde Success portraitOlatunde Success
  • Date:  8 March 2026
  • NestJS

Idempotency Keys: The Cheapest Insurance in Money-Movement APIs

A practical guide by Olatunde Success to implementing idempotency keys in NestJS payment APIs: request hashing, response replay, race handling, and the failure modes that make them mandatory in fintech.

Networks fail mid-request. Mobile users double-tap. Payment providers retry webhooks. In a normal API these produce duplicate rows; in a payments API they produce duplicate transfers. Real money, gone twice. Idempotency keys are the cheapest insurance you can buy against that, and I put them on every money-movement endpoint I ship, from Cirva wallets to core banking APIs.

The mechanics

The client generates a unique key per logical operation and sends it as a header. The server stores the key with a hash of the request body and, once processing completes, the response. A retry with the same key and same body gets the stored response replayed; the operation itself runs exactly once. A reused key with a different body is a hard error, because that is a bug on the client, not a retry.

The details that bite
  • Concurrency: two requests with the same key racing each other must collapse to one execution. A unique constraint in Postgres plus insert-first-then-process beats any in-memory lock.

  • Scope keys per endpoint and per user, or one client’s key can collide with another’s.

  • Set an expiry window. Keys kept forever mean unbounded storage; 24 to 48 hours covers realistic retries.

  • Store the response, not just a done flag. A replay that cannot return the original result is a new failure mode.

Providers retry more than you think

Working with Nigerian rails, including Paystack mandates, SafeHaven virtual accounts, and Sudo card events, taught me to treat every inbound webhook as guaranteed at least once. The same discipline applies inbound and outbound: process webhooks idempotently by event ID, and send your own provider calls with idempotency keys where the provider supports them.

If an endpoint moves money and is not idempotent, it is not unfinished. It is broken. Someone just has not hit the failure yet.

More from the blog

Want to talk about this article or a project?

© 2026 Olatunde Success. All rights reserved.

Built in Ibadan, Nigeria

background