Idempotency
Safe retries for money-moving requests : keys, replay, and what "safe" means.
Every financial mutation requires an Idempotency-Key header. It is what
makes retries safe: losing a response, a timeout, or a client retry can never
create a duplicate transaction.
The contract
curl https://api.ouipay.com/v1/payments \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: pay-2026-0001" \
-H "Content-Type: application/json" \
-d '{ "customer_id": "01M2S17...", "amount_minor": 50000, "currency": "NGN", "method": "card" }'- Required on all money-moving
POSTs: payments, transfers, exchanges, refunds, funding - Replay-safe: re-sending the same key returns the original response (same transaction id), not a new operation
- Scoped: per endpoint; the same key on
/paymentsand/transfersare independent operations
How replay works
Request arrives → key checked → if seen, return the stored response
→ if new, process and store the result under the keyThe dedupe is a database uniqueness constraint, not an in-memory check: it survives restarts and races. Two concurrent requests with the same key: one wins, the other gets the winner's response.
Generating keys
Use a unique, deterministic value per logical operation:
order-42-attempt-1: your system's id for the operation- A UUID generated at submit time and stored with the user's intent
Do not reuse keys across different operations, and do not use a per-request random value on a retry: a retry must reuse the original key.
What replay returns
The stored response: including its original status. If the first attempt failed, the replay returns that same failure (it does not re-run the operation). To retry a failed business operation, submit a new request with a new key.
The unknown case
A transaction in unknown must not be blindly retried: the provider may have
processed it. The idempotency key alone cannot rescue a retry if the first
attempt reached the provider. Wait for the webhook or query status; only
re-submit (new key) once the original is failed or completed.
Key reuse is not retry safety
Reusing a key returns the first result: it does not retry the operation. Retrying means: same key for transport safety, new key only after the original is definitively done.
Retention window
Keys are honored for 24 hours. After that a key is treated as new: do not rely on replay beyond the window for recovery.