Idempotency — clientOrderId
Make order placement safe to retry under network failures and reconnects.
POST /v2/orders and POST /v2/orders/batch accept an optional but strongly
recommended clientOrderId field. A second request with the same
clientOrderId does not create a new order — it returns the original one
with "idempotent": true.
Format
clientOrderId regex: ^[a-zA-Z0-9_-]{1,64}$UUID v4 is recommended:
- Node.js:
crypto.randomUUID() - Python:
uuid.uuid4()
→ 550e8400-e29b-41d4-a716-446655440000
Behavior
| Scenario | Response |
|---|---|
First POST with clientOrderId=X | 200 OK, new order |
Same POST again with clientOrderId=X | 200 OK, same order, "idempotent": true |
Different account using clientOrderId=X | 409 Conflict, "clientOrderId already used by another account" |
Why it matters
- Network glitches (504 / 502 / 408) trigger client retries → duplicate-order risk.
- Tab restoration, double-clicks, websocket reconnects can fire the same logic twice.
- Without a
clientOrderId, the backend generates a fresh UUID for every request — so retries silently duplicate.
Example
import uuid
client_order_id = str(uuid.uuid4())
resp1 = post_order(symbol="BTCUSDT", quantity="0.01", client_order_id=client_order_id)
# Network drops here, client retries:
resp2 = post_order(symbol="BTCUSDT", quantity="0.01", client_order_id=client_order_id)
assert resp2["idempotent"] is True
assert resp1["order"]["id"] == resp2["order"]["id"]Treat clientOrderId as load-bearing. Generating it once per intent
(not per attempt) is what makes retry safe.