Skip to main content
Network failures happen mid-request. Idempotency lets you retry a write without risking a duplicate trade. There are two mechanisms. The Idempotency-Key header works at the HTTP layer on every write route listed below. The clientRequestId body field works at the trade level on POST /v1/trades. Use either, or both.

Idempotency-Key header

Generate one key per logical operation, for example a random UUID. Keys are at most 255 characters from A-Z a-z 0-9 _ - : . (400 IDEMPOTENCY_KEY_TOO_LONG or 400 IDEMPOTENCY_KEY_FORMAT_INVALID otherwise). Honoured on: POST /v1/trades, POST /v1/trades/{id}/confirm, POST /v1/redemptions, POST /v1/markets/{id}/disputes and POST /v1/webhooks/events/{eventId}/redeliver. Keys are scoped per user and per route. Behaviour:
  • First request: runs normally. A 2xx response is stored under the key for 24 hours.
  • Same key, same request: the stored response is returned with its original status and body, plus the header Idempotent-Replay: true. Nothing runs again.
  • Same key, different request: 409 IDEMPOTENCY_KEY_CONFLICT. “Same request” means the same method, URL and JSON body.
  • Same key while the first request is still running: 409 IDEMPOTENCY_REQUEST_IN_PROGRESS. Retry a few seconds later with the same key to get the original response.
  • Errors are not stored. A 4xx or 5xx releases the key, so you can fix the request and retry with the same key.
  • After 24 hours the key is forgotten, and a request with it runs as new.
Because a replay returns the stored body unchanged, check the Idempotent-Replay header rather than _meta.idempotent to detect an HTTP-level replay.

clientRequestId body field

clientRequestId is stored on the trade itself (1 to 128 characters from A-Z a-z 0-9 _ - : .):
  • First request with a given value: the trade is created (201).
  • Same value, same body: the existing trade is returned with 200 and _meta.idempotent: true. No new trade.
  • Same value, different body: 409 CLIENT_REQUEST_ID_CONFLICT.
It has no 24-hour limit, and you can see it on the trade, which makes it the right choice for meaningful ids from your own system and for long-lived batch jobs.

Using both

They layer cleanly. The header absorbs transient HTTP retries; clientRequestId guarantees one trade per logical order for as long as the trade exists. The TypeScript SDK sends an Idempotency-Key on every POST automatically.

High-value trades

A trade at or above your key’s high-value threshold returns 202 with a one-time confirmation token. Retrying the create with the same Idempotency-Key returns that same stored 202, with the same token, and creates nothing. The token itself is single-use: a second confirm returns 409 CONFIRMATION_TOKEN_USED. If you lose the confirm response, read the trade with GET /v1/trades/{id}.

Conflict response

Don’t retry with the same key and the new body. Either send the original body again to get the original response, or use a new key for the new request.

Routes without Idempotency-Key

  • POST /v1/auth/api-keys/me/webhook-secret/rotate rotates on every call, guarded by a 60-second cooldown (429 WEBHOOK_SECRET_ROTATION_COOLDOWN). Don’t retry it blindly: see Secret rotation.

Next

Pagination

Cursor pagination on every list endpoint.

ETags

Conditional requests for cheap polling.