Idempotency
Network failures, timeouts, and worker restarts make retries unavoidable. The Idempotency-Key header lets you retry a write request without risking duplicate side effects: the first successful response is cached for 24 hours, and any subsequent request with the same key is replayed verbatim from cache.
When to Use
Send Idempotency-Key on every state-changing request where a duplicate would be problematic — creating invoices, posting payments, bulk imports, etc.
The header is optional. If omitted, the request is processed normally without idempotency protection.
How It Works
- The client generates a unique key (UUID/ULID recommended) and sends it in the
Idempotency-Keyheader. - On the first request with that key, the server processes normally and caches the 2xx response.
- On a retry with the same key:
Content-Type: application/json(JSON tier) — body is compared using a SHA-256 hash:- Same body → cached response returned with
X-Idempotent-Replayed: true. - Different body →
422 Unprocessable Entity(catches accidental key reuse with mutated payload).
- Same body → cached response returned with
- All other content types (e.g. multipart file uploads) — key-only match: a retry with the same key returns
422 Unprocessable Entity, since the binary body cannot be hashed to confirm it matches the original. Use a new key for a new request.
- If a retry arrives while the first request is still being processed →
409 Conflict. Retry after the original completes.
Example
If the same request is retried with the same Idempotency-Key and body, the response is identical, no new invoice is created, and the response includes:
Key Format
Invalid keys are rejected with 400 Bad Request.
Scope and Lifetime
Idempotency-Key value can be safely reused across different endpoints — they will not collide.Response Codes
Applicability
Idempotency-Key takes effect on all POST requests under /v1/*. Each endpoint that supports it lists Idempotency-Key in its parameter table — refer to the per-endpoint API reference.
The header is ignored (no caching) for:
- Non-
POSTmethods (GET,PATCH,PUT,DELETE— currently) - Requests without an API key
For multipart file uploads and other non-JSON content types, the server cannot verify the request body without loading the full upload into memory. A retry with the same key always returns 422 — use a new key for each new upload.

