Overview
A request times out. You do not know whether the order was placed. Retry, and you might end up with two positions. Do not retry, and you might have none. Neither guess is acceptable when the difference is real money, and “check first, then retry” does not close the gap either: the order can land between your check and your retry.Idempotency-Key removes the guess entirely. This guide covers using it correctly, the one mistake that silently defeats it, and the specific case where the usual advice is wrong.
Read time: about 10 minutes. Short by design. This is one idea applied carefully, not a large surface to learn.
TL;DR
- Every mutating request accepts an
Idempotency-Key. Retry with the same key and you get the original response back instead of a second order. - The key identifies one intended action, not one HTTP attempt. Generate it outside your retry loop.
- Generating it inside the loop defeats the mechanism completely and silently.
- On
429, honourRetry-Afterand add jitter. - Provisioning a user is the one place a deterministic key beats a random one.
- A pending withdrawal is not a failed one. Do not resubmit it.
What you will do
- Attach an idempotency key to a mutating request
- Write a retry loop that is actually safe
- See why the common mistake is invisible until it costs you
- Choose between random and deterministic keys deliberately
- Handle
429without extending your own rate limiting - Handle the withdrawal case, which behaves differently
What you will need
Knowledge- Basic HTTP retry patterns
- A Bravado API key with
trade.execute
The mechanism
A retry loop that works
The mistake that defeats it
Random or deterministic
When deterministic is better
Provisioning a user is the clear case:Which calls need one
Anything that changes state:- Orders:
POST /v2/trade/order,POST /v2/trade/order/batch - Cancels:
DELETE /v2/trade/orders/{order_id},POST /v2/trade/orders/cancel-batch,POST /v2/trade/orders/cancel-all - Positions:
POST /v2/trade/positions/redeem,/split,/merge - Copytrade:
POST /v2/trade/copytrade,PATCH,DELETE - Combos:
POST /v2/trade/combo/quote,/accept,/redeem - Users:
POST /v2/trade/users - Withdrawals:
POST /v2/trade/withdraw
Handling 429
Rate limiting is where retries commonly make things worse.The withdrawal case
Withdrawals have a state that no other endpoint has. If the transaction does not confirm inside the latency budget, you get:Wrapping up
One header, one rule: the key identifies the intention, so it must exist before the first attempt. Everything else follows. Random keys for actions that could legitimately repeat, deterministic keys for actions that never should,Retry-After honoured with jitter, and pending treated as pending rather than failed.
Frequently asked questions
What happens if I retry with the same key?
What happens if I retry with the same key?
You get the original response back, marked as a replay. No second order is created.
Can I reuse a key with different parameters to amend an order?
Can I reuse a key with different parameters to amend an order?
No. The key is bound to the original request. To change an order, cancel it and place a new one with a new key.
How long is a key remembered?
How long is a key remembered?
Long enough to cover a retry window. Do not rely on it as a long-term deduplication store for your own business logic; keep your own record of what you intended.
Do read requests need a key?
Do read requests need a key?
No. Only mutating requests change state, and only they can be duplicated harmfully.
Should I use a hash of the payload as the key?
Should I use a hash of the payload as the key?
Rarely. It works, but it means two genuinely separate identical orders collapse into one. Only choose it when that is precisely the behaviour you want.
My withdrawal returned STATE_PENDING. Did it fail?
My withdrawal returned STATE_PENDING. Did it fail?
No. It was broadcast but not confirmed within the latency budget. Poll
GET /v2/trade/activity?type=WITHDRAW and match the transaction_hash rather than resubmitting.Resources
- Idempotency reference, header behaviour and replay semantics
- Rate limits, quotas,
Retry-After, and backoff - White-label sub-accounts, the deterministic-key case
- Place an order, where you will use this first
- Build a trading bot, retries inside a running loop
- Error reference, status codes and their causes