Idempotency keys
Network requests fail. Mobile keyboards double-tap submit
buttons. A retry-on-timeout that re-sends a POST can mint a
second order the customer never wanted. The Driftstack API
uses the standard Idempotency-Key request header
to make safe-to-retry mutations actually safe.
How it works
Send a unique opaque token on the
Idempotency-Key request header. The first request
with a new token is processed normally. Any subsequent request
to the same endpoint with the same token, scoped to the same
caller, returns the original response verbatim — same body,
same Location, same minted IDs.
POST /v1/billing/crypto-checkout
Authorization: Bearer $KEY
Idempotency-Key: 7b3f2e0c-1b6a-4cf3-aa6d-9c2c1f8a1b22
Content-Type: application/json
{
"product": "team_manual",
"price_cents": 4900,
"price_currency": "USD"
} When the response is a replay (i.e. the server is returning a previously-minted result rather than performing the work again), it sets:
Idempotent-Replayed: 1 Most clients can ignore this header; it's useful for analytics and for debugging "why does my dashboard show this order twice".
Where it applies
POST /v1/billing/crypto-checkout— mints a crypto order. Without the header, two racing clicks mint two orders; with the header, the second click returns the first order.
Future write endpoints will adopt the same convention; this page will enumerate them. Read-only endpoints do not consult the header.
Choosing a key
- Use any opaque string up to 255 ASCII characters (no whitespace). UUIDv4 is the canonical choice and what Driftstack's own GUI client mints.
- Generate one per intent, not per request. If a single submit button could be clicked twice, all retries of that submit use the same key.
- Don't include user data in the key — keys appear in server logs.
Scope + lifetime
- Keys are scoped per account. Two
different accounts sending the literal string
k1get two independent orders. - The dedupe window is 24 hours from the first sighting. After that the key is forgotten; reusing it mints a fresh order.
- Pre-signup checkouts (no account_id) share a single anonymous bucket. Don't rely on uniqueness there if your client is one of many anonymous callers.
Errors
- A key longer than 255 characters returns
400 Bad Request. - A key containing whitespace returns
400 Bad Request. - A missing header is not an error — the endpoint behaves as if idempotency were not requested.
We do not reject replays where the request
body differs from the original — if you send k1
with price_cents=4900 first, then k1 with
price_cents=9900, you still get the original 4900-cent order
back. The server records the mismatch and surfaces
it as body_mismatches on the admin
GET /v1/admin/crypto-orders/idempotency-metrics
counter, so support can spot client bugs where a key is being
reused across intents. Mint a fresh key per intent and this
is a non-issue.