Skip to content

Best practices

Efficient requests, forward-compatible parsing, and reading the headers.

Read confirmation clocks separately from price changes

Section titled “Read confirmation clocks separately from price changes”

A newer last_update is a newer confirmation, not necessarily a changed price. Compare the outcomes themselves, including their prices, points and sizes, to detect a price or line change. A game-market clock is conservative: when several rungs are combined it uses the oldest included rung confirmation. Game-market outcomes do not carry separate clocks. A streaming book’s fixture-level clock can also advance when its connection proves it is alive, without a new price message. These clocks do not measure when the upstream price first moved. The live-feed guide explains unchanged confirmations.

ISO timestamps always use UTC with exactly three fractional digits and a trailing Z, for example 2026-09-29T07:50:29.043Z. Sub-millisecond digits are truncated. Preserve the fraction when comparing updates: 2026-09-29T07:50:29.043Z and 2026-09-29T07:50:29.817Z are different confirmations. With dateFormat=unix, last_update can be a fractional number such as 1790668229.043. With dateFormat=unix, fixture and gameline archive times use whole seconds. Accept fractional price clocks and preserve them when comparing updates.

bookmakers and markets both narrow a response; eventIds narrows a list call to specific fixtures. A smaller response is faster to parse and does not change what counts against your allowance, since every odds, props or history call counts once regardless of size.

Read the rate-limit headers, do not guess them

Section titled “Read the rate-limit headers, do not guess them”

Every response, including error responses, carries X-RateLimit-Remaining, and every response that reached your usage record carries x-requests-used and x-requests-remaining (a rejected key or a 429 SPEED_LIMIT does not, so keep your last known values). Back off when X-RateLimit-Remaining reaches zero instead of waiting for a 429, and read Retry-After on a 429 rather than a fixed sleep. The Speed limits and errors page lists every header and every error code.

error.code, size.kind, a bookmaker’s kind, and a plan name can all gain a new value within /v1, deliberately: the OpenAPI file marks each of these x-extensible-enum rather than a closed enum so a value your client does not recognize yet is still valid JSON, not a parse failure. Write the fallback branch now.

Never assume a book you asked for is in the response

Section titled “Never assume a book you asked for is in the response”

A book with no price for a fixture is absent from bookmakers[] and named in unmatched_bookmakers[] instead of being dropped without a trace, whatever the reason: it does not list the fixture, it has none of the markets you asked for, it could not be safely matched to the fixture, or what it had was too old. When you pass bookmakers=, the list covers the books you asked for; without it, game odds cover every catalogue book and props cover every props-capable catalogue book. The accounting uses the selected markets on both request shapes. This list does not identify the reason for absence or prove an outage. Check both before concluding a book has no line.

A null last_update means the latest confirmation time is unavailable. It is never an estimate and never means the price is old. Do not treat it as a missing or stale price.