Skip to main content
Every create that moves money requires an Idempotency-Key header. This is not advisory. A request without one is rejected.

The problem it solves

A request times out. You do not know whether it arrived. Retrying risks a second payment; not retrying risks none. Without a key there is no safe answer. With a key there is: retry the identical request with the same key. If the first attempt landed, you get that same result back rather than a second movement.

The three outcomes

The third case is the important one. The key is bound to the exact input, so it cannot be recycled across different operations. If you change an amount, a destination or an account, you need a new key. While a request is still being processed, an identical retry returns request_in_progress (409). Wait and read the resource rather than retrying immediately.

Choosing a key

Check the operation’s header schema for its limits. Funding-account issuance (POST /v2/accounts/{accountId}/onramp-bank-accounts) requires 8–256 printable characters after trimming surrounding whitespace. A stable namespaced key such as bank-funding:acct_123:v1 meets that requirement.
  • Derive it from your own operation, not from a random value generated at call time. A UUID created inside your retry loop changes on every attempt, which defeats the purpose.
  • A good key is your order id, invoice id or payout batch id, namespaced by operation: payout:invoice_8891. It survives a process restart and is the same on every retry.
  • Do not reuse a key across environments. Keys are scoped per app environment.
Generating the key at the moment of sending is the most common mistake. If a timeout triggers a retry with a fresh key, you have created a second payment.

Where keys are required

The key is required on these creates, and a call without one is refused: Bank linking and rail-identifier keys must contain 1–256 characters after trimming surrounding whitespace. The key is optional, and honoured when sent, on POST .../deposit-addresses. Send one anyway: it is what makes a timed-out retry safe. Outgoing Payment confirmation uses the pending actionId and proof rather than an idempotency key. Reads never require a key, and sending one has no effect.

What a key does not do

  • It does not make an operation reversible. It prevents duplication, not commitment.
  • It does not extend across resources. A key used for a payment has no bearing on a later refund of that payment.
  • It does not replace reading state. After a retry returns, read the resource before acting on it.

Next

Errors

Every error code, and which are safe to retry.

Status codes

What each state means once the request has landed.