Shipmind Labs

Retries are not a safety feature. They are a duplication feature, unless the receiver can tell a repeat from a new request.

Every team adds retries eventually. The network times out, the client resends, and now the same payout exists twice. The usual fix is an idempotency key. The usual mistake is generating that key from the HTTP request: a hash of the body, a header the client sets fresh on every attempt, a UUID created inside the retry loop. All of those change when the caller changes, so the second attempt looks brand new to your system.

The key has to belong to the business operation, not the transport. It gets allocated once, when the intent is formed (this payout, for this order, for this period), and it survives the client restarting, the queue redelivering, and the operator clicking twice.

The second half gets skipped more often than the first. Recognising a duplicate is not enough. You have to store what the original attempt produced, then return that same stored result, byte for byte. If a repeat re-runs the handler and merely suppresses the side effect, the caller gets a different response for the same operation, and reconciliation later cannot tell which answer was true. The key maps to the outcome, not to a boolean "already seen".

We build this into payment services and ledger flows by default now, because every provider on the other side assumes we handle replays, and most of them are right to assume it.

So it is worth knowing where your idempotency key actually gets created: inside the client's retry loop, or at the moment the business intent is recorded.

Was this useful?

Building something similar?

or email hello@shipmindlabs.com