Use idempotency keys
Make state-changing API calls safe to retry by reusing one Idempotency-Key per logical operation.
Network failures can leave you unsure whether a server-side write reached a 0Bit product API. Idempotency keys let you retry the same logical operation without creating duplicate sessions, checkouts, quotes, customers, trades, or fulfillment records.
Same operation, same key
Generate one idempotency key for the logical operation and reuse it for retries of the same request body. Do not generate a new key for every retry.
Retry decision
Key design
| Scope | Example format | Why |
|---|---|---|
| Checkout session | checkout:<attemptId> | Prevents duplicate hosted sessions. |
| Quote lock | quote:<quoteRequestId> | Keeps a retry tied to one quote request. |
| Customer create | customer:<accountId>:<version> | Prevents duplicate customer records. |
| Pool transaction | pool-tx:<intentId> | Required header on the 0Pools transact (money write); keeps execution retry-safe. |
0Pools: the key goes on transact
For 0Pools, the Idempotency-Key header is required on transact — the money write — not on quote creation, which does not require it. Beyond the header, transact is also idempotent on the quote's quoteId: reusing a key with a changed request body returns 409.
Server pattern
async function createProductWriteWithRetry<T>(input: {
intentId: string;
operation: (idempotencyKey: string) => Promise<T>;
}) {
const idempotencyKey = `product-write:${input.intentId}`;
return retryTransient(async () => {
return input.operation(idempotencyKey);
});
}Guardrails
| Do | Avoid |
|---|---|
| Store the key with your local attempt. | Recomputing a different key after a restart. |
| Retry only identical request bodies with the same key. | Reusing a key after changing amount, currency, or user reference. |
| Keep the same key through network retries. | Parallel retry storms. |
| Pair idempotent writes with idempotent fulfillment. | Assuming API idempotency protects your own ledger. |