Launch offer: the first 1,000 users get Settl free for a year*Claim your spot
settlbuilding in public

Idempotency and Safe Retries

A timeout does not tell you whether the action failed. It only tells you the response did not arrive.

If the first charge, order, or message succeeded and the client retries with a fresh identity, the server sees a new request and performs the work again. Safe retries need one stable identity created before the first attempt.

The request contract

The client sends an idempotency key with the request. The server stores:

The first request claims the key atomically. A duplicate with the same fingerprint waits for or replays the original result. The same key with a different fingerprint is a conflict, not a retry.

Create the key once:

checkout begins
  -> create or derive operation key
  -> save it with the pending client action
  -> reuse the same key on every network attempt

Do not call uuid() inside the retry loop. That creates a perfect new identity for every duplicate.

Deterministic IDs without leaking input

Some operations already have a natural identity: tenant, cart, order version, and operation type. Canonically serialize those fields so field order and whitespace cannot change the result. Add a versioned namespace so a future recipe does not collide with the old one.

Do not publish a raw hash of an email, phone number, or other guessable private value. Use a server-side keyed digest when sensitive fields contribute to the ID, or mint an opaque ID once and store the mapping.

Deterministic does not mean "same customer and amount forever." The scope must distinguish two legitimate purchases of the same item. Write down the business boundary before deriving the key.

Concurrency and retention

Two copies can arrive at the same millisecond. The key record needs a unique constraint or equivalent atomic claim, with one owner and a visible in-progress state. Persist the business result and replayable response before reporting success.

Keep records long enough to cover the real retry window. Expiring them too early turns an old retry back into new work. Keeping them forever creates an unbounded table and can block legitimate repeats. Retention is part of the API contract.

Verification checklist

  1. Send the identical request twice. The side effect runs once and both callers receive the same result.
  2. Release two identical requests concurrently. Exactly one owns the work.
  3. Reuse the key with a changed payload. The server returns a conflict.
  4. Reorder JSON keys and prove the canonical fingerprint stays the same.
  5. Simulate a process crash after the side effect but before the response. The retry finds and returns the stored result.
  6. Exercise expiry and confirm a legitimate new operation gets a new identity.

The starter returns a request-fingerprint contract, stable-ID recipe, duplicate behaviour, replay response, conflict policy, and retention tests. Dry-run is the default and executes no payment, order, email, or production write.

Download the runnable pack

Use IDEM for retry safety and DETERM for deterministic IDs.

Get the next one in your inbox