Skip to main content
Idempotency ensures retries are safe for mutating requests. Retrying the same request with the same Idempotency-Key never executes side effects twice.

How it works

Include an Idempotency-Key header on every request to an endpoint that requires one. Natural records the key alongside the outcome of the request, and a later request with the same key returns that recorded outcome instead of running the operation again.
On subsequent requests with the same key:
  • Same key + same request + finished -> Replays the recorded response.
  • Same key + different request -> Returns 409 conflict.
  • Same key + original still running -> Returns 409 conflict.
  • Different key -> Treated as a new mutation attempt.
Replayed responses include X-Idempotency-Replayed: true. That header is the only thing distinguishing a replay from a fresh execution, so check it if you need to tell them apart.

Endpoints that require a key

The Idempotency-Key header is required on the endpoints below. Each one is a mutating operation whose accidental repetition would be visible to you or your customers. Omitting the header on any of these returns 400 with the error code invalid_value. A key longer than 255 characters is rejected the same way. Endpoints not listed here ignore the header.

Keys

A key must be unique per logical operation and stable across every retry of that operation. Natural binds the key to the meaningful contents of the request it first arrives with, so the same key must always mean the same request.
  • Use a UUIDv4/UUIDv7, or any unique string of up to 255 characters.
  • Generate the key once, when the operation is first attempted, and reuse it for every retry of that attempt, including retries after a timeout.
  • Generate a new key only when the user or system starts a genuinely new operation.
  • Never derive a key from anything that changes between retries (a timestamp, an attempt counter, a per-request random value). A key that changes per retry provides no protection at all.
  • Don’t put sensitive data in keys.
Keys are scoped to the party the request acts on. Two parties can use the same key string without interfering, and a key is never shared across parties.

Replay window

A record is created when the request starts, and is finalized once the operation reaches a terminal outcome: success or failure. The record then expires 48 hours after it finished, not 48 hours after the request arrived. Within those 48 hours, the same key replays the recorded outcome. Once they elapse the key is forgotten, and reusing it starts an entirely new request, re-running the side effect. Treat 48 hours as the window in which a retry is guaranteed safe, not as a deduplication guarantee for the life of the key. A record for an operation that is still running does not expire on its own. If an operation never reaches a terminal outcome, its key stays reserved and requests reusing it keep returning 409 conflict. Contact support if a key stays conflicted longer than you would expect.

Conflicts

Both conflict cases return 409 with the error code conflict:
The response body is identical in both cases, so tell them apart by what your own client did:
  • You retried an identical request. The original is still running. Wait, then retry the same key with exponential backoff.
  • You changed the request but reused the key. This is a client bug: a key is bound to the first request sent under it. Use a fresh key for the new operation.
Include meta.supportId when contacting support about a conflict; the underlying reason is recorded against that ID.

Failures are replayed too

Failures are recorded exactly like successes. When an operation fails terminally, the same key replays that same error (identical code, status, and detail) for the rest of the window. Retrying a recorded failure with the same key does not re-run it. Two cases release the record rather than recording it, because neither reflects a decision about your request: 408 (timeout) and 429 (rate limited). Retrying either with the same key genuinely re-runs the operation.

When to retry

Don’t switch to a new key to force a failed operation to re-run. A new key is a new operation: if the original moved money before failing, a fresh key can move it a second time. Check the resource’s status first, and only re-attempt under a new key once you have confirmed the original did not take effect.