Data & sources
How we acquire the odds
We read the interfaces published by the ADM-licensed operators — the endpoints that power their own schedules — and expose them normalized into a single schema. Part of the catalogue (including bet365 and Pinnacle) comes from third-party data providers under licence, not from the operator. Every quote stays attributed to the book it belongs to, with its last_update.
Verifiable from two different reads, which do not give the same number: GET /api/v1/bookmakers (requires an API key) lists the active keys in the feed with country, playable_it, is_exchange and source — how many keys you can query, counting separately the dedicated market lanes such as <brand>-corners; GET /api/v1/coverage (public, no key) counts the brands per region — how many brands you are covering, with the lanes grouped under their own brand. There is no one-to-one match between the two counts: they measure different things.
How we normalize them
- Deterministic event_id: the same fixture has the same id across all markets and for the whole pre-match window — that is how we compare books with each other (non-heuristic matching).
- Stable, versioned schema (OpenAPI 3.1): the engine's internal shape never reaches the client.
- Complete market capture: for every event we expose all the markets the book prices (result, O/U, handicap, correct score, half-time/full-time, combinations and book-specific markets such as
other:<label>), not just the main ones. - No arbitrary merging of books: every feed key stays a key and the response never merges different brands into a single row — if you need to group them, you decide how. The only grouping is in the per-brand counts of GET /api/v1/coverage, where the dedicated market lanes (
<brand>-corners) fall under their brand.
Verifiable: GET /api/v1/leagues shows sport → leagues with event and book counts in the current schedule.
Freshness and correctness
- Every quote carries its
last_update(ISO) — the timestamp is that of the last successful fetch: a book in error never shows stale data with a fresh timestamp. - The real distribution of staleness (p50/p95/p99 over 24h, per book) is public on the status page. Measured, not declared.
- We do not invent data: a line/handicap whose sign cannot be derived with certainty is discarded, not guessed (this avoids false arbitrages).
- Markets that are not comparable across books (
other:*, player markets, Asian totals) are exposed as data but never promoted to arbitrage. - We do not apply filters that do not exist: an unknown query parameter returns
400with the list of those accepted on that endpoint (and a suggestion, if it is a typo), never200with the unfiltered feed. The error does not consume quota.
Coverage and seasonality
We have no list of leagues we follow or exclude: if a book prices an event, we see it. Which markets appear depends on the season — with the championships on hold the football schedule is thin (friendlies), and it fills up again when they restart. The real count, moment by moment, is on /api/v1/leagues and on the status page.
Licence and redistribution
Internal use included in every plan: your own models, bots, analysis, tools.
Redistribution to end users (showing the odds inside a product/SaaS of yours: pre-match search, comparison, calculators, workflows) → requires the Enterprise / redistribution licence, not the standard Starter/Pro plans. It is a core constraint for a SaaS, not a footnote. Full text in the Terms and in the Enterprise licence.
Support
Write to [email protected] or through the little robot on the site. A serious problem is picked up within 4 business hours (target); paid plans have priority.