Best practices
Correctness, cost, and resilience rules that follow from how the API actually behaves.
Each rule below follows from something documented elsewhere. The reasoning is included so you can decide when it does not apply to you.
Correctness
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.
Cost
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.
Resilience
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
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.
Keys and secrets
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.