Skip to main content

Idempotency and retries

Every write requires an Idempotency-Key header. Without one the call is refused with missing_idempotency_key (400). This applies to create, link, session and cancel.

Idempotency-Key: 1e6f6a1c-2c4e-4d7e-9d0e-7a1f5c2b8f3a

🔁 What happens on a retry​

What you doWhat happens
Retry with the same key and the same bodyThe original result, no second payout
Retry a key whose first attempt was rejectedThe same error again — even after the cause is fixed. Use a new key
Same key, different bodyidempotency_key_conflict (409)
Retry while the first attempt is still running409 attempt_unresolved with operation_status: pending — retry it, do not treat as a failure
New key, an existing merchant_reference, same amount, delivery and recipientThe existing payout, no second payout
New key, an existing merchant_reference, different detailsmerchant_reference_conflict (409), with the existing payout in detail.payout_id

🧩 Two separate ideas — you need both​

  • Idempotency-Key — identifies one attempt. Change it only when you intend a new payout.
  • merchant_reference — your own id for the payout. Permanently unique per account, so it is what you use to find the payout again later (see List payouts). It is also a second guard: even with a new key, the same reference never produces a second payout.

🚫 After a rejection​

A rejected create is final for its key. Retrying the same key replays the same error — it does not re-check your balance or limits. When the cause is fixed (balance topped up, the hourly limit reset), send the request again with a new Idempotency-Key. Branch on the error code, not on the HTTP status.

⏳ attempt_unresolved​

{
"operation_status": "pending",
"payout_id": null,
"error": "attempt_unresolved",
"message": "the outcome is not established; retry this attempt with the same Idempotency-Key"
}

This one 409 is the exception to "do not retry a 409": the outcome is not yet established. Cancel can return it too, when the account was busy with another change at that moment. Retry the same call with the same key until you get a definite answer — it can never create a second payout.

Keep holding the amount on your side

Until you get a definite answer, do not treat attempt_unresolved as a failure. Doing so would release a hold on a payout that may well exist.

🔗 Replays and payout_url​

A retry of the same key replays the same payout with payout_url: null — a replay must not mint a fresh secret. Store the link when you first receive it, or fetch it again with Get or rotate claim link.