Skip to content
Get an API key

Each rule below follows from something documented elsewhere. The reasoning is included so you can decide when it does not apply to you.

Check capability before assuming support. Read the venue’s has map or the capabilities field rather than discovering a gap through a caught exception. Eighteen venues genuinely differ, and NOT_SUPPORTED is an answer rather than a fault. See Capability-honest data.

Never render a synthetic book as depth. Venues without a real order book return a book-shaped response labelled synthetic. It is a faithful representation of price and is not orders anyone can fill against. Feeding it into a sizing calculation produces a number with no meaning.

Do not equate similar markets across venues. Matched clusters carry a similarity score, not an identity claim, and two venues can settle what looks like the same question differently. A price gap is an indicative price discrepancy until every executable gate passes.

Use asOf, not your own clock. A timestamp you generate on receipt describes your request. asOf describes the data.

Persist marketId, not slug. Slugs derive from titles and change when a venue renames a market. See Identifiers.

Follow cursors instead of parallelising offsets. nextCursor freezes the catalog snapshot from page one, so a long walk never skips or double-counts rows that move while you page. Parallel offset pages give up that guarantee and spend the rate allowance faster.

Batch where a batch verb exists. fetchOrderBooks takes many outcomes in one request. It is priced by items, so it saves rate allowance rather than credits.

Stream rather than poll. A WebSocket subscription delivers book and trade updates without consuming the request window at all. Polling a book every second is the most expensive way to get data that is pushed for free.

Cache what does not move. Capability maps and taxonomy change rarely. Re-fetching them per query is pure overhead.

Request only the window you need. History is priced per query regardless of range, but a narrower window returns faster and is less likely to hit a lane bound.

Branch on code and retryable, not on HTTP status. Several codes share a status, and retryable is the field that answers the question you are actually asking. See Errors.

Retry only 429 and 503, with exponential backoff and jitter. Everything else fails identically on the second attempt. INSUFFICIENT_CREDITS in particular will not resolve by retrying.

Never auto-retry a write. A submit, cancel, or modify that may have reached the venue must not be replayed by a client library. Retry deliberately, with an Idempotency-Key. See Trading & execution.

Expect empty results to be legitimate. A market with no trades today returns an empty tape. fetchSeries on a venue without the concept returns an empty list. Neither is an error.

Handle 503 on writes while reads keep flowing. When rate limiting is degraded, reads fail open and side-effecting routes fail closed. That asymmetry is deliberate.

Send keys in the Authorization header, never in a query string. Query strings end up in request logs, browser history, and referrer headers.

Keep keys server-side. The raw key is shown once and stored only as a hash. A key that reaches a browser bundle is disclosed permanently and must be revoked.

Use separate keys per environment. Rate limits and credit spend are tracked per key, so one key across staging and production makes both untraceable and lets a test loop exhaust a production allowance.