How idempotency keys make POSTs safe to retry - semantics, expiry, conflicts, and per-SDK behavior.
Networks fail between "server did the work" and "client got the response." Without idempotency, retrying a POST can create the resource twice. The Idempotency-Key header makes retries safe.
signup_10492_project).| Rule | Behavior |
|---|---|
| Key scope | Per API key + endpoint + HTTP method |
| Lifetime | Keys expire 24 hours after first use |
| Conflict | Same key + different body → 409 idempotency_conflict |
| Applicability | POST only - GET/PATCH/DELETE are already idempotent |
| Response | Replays status + body + Idempotent-Replay: true header |
HTTP/1.1 201 Created
Idempotent-Replay: trueAll official SDKs attach a key automatically to every POST - retries within the SDK's maxRetries reuse it, so default SDK calls are already safe:
await client.projects.create(params); // auto key
await client.projects.create(params, {
idempotencyKey: `provision-${customerId}`, // yours instead
});provision-customer-884. Bad: Math.random().{
"error": {
"type": "conflict",
"code": "idempotency_conflict",
"message": "This idempotency key was already used with a different request body.",
"request_id": "req_2hF8kLm4xQ"
}
}If you get this, the key was already consumed by a different payload - generate a fresh key. This is what prevents "same key, different intent" bugs from silently replaying.