OddsPapi aggregates bookmaker prices; it is not an official or licensed league-data provider. Settlement is derived from resolved cross-source facts, and futures settlement is rolling out — the endpoint exists but does not yet serve results.
The pipeline
1
Discover the catalog
GET /sports, /tournaments, /seasons, /participants, /players, /venues — the static tree your product is built on. Cache it; it changes slowly.2
Load the schedule
GET /fixtures, /fixtures/today, /fixtures/live for snapshots, then the fixtures channel for status and schedule changes.3
Model markets
GET /markets?sportId=… gives every market and its outcomes for a sport — the offer you can present.4
Price it
GET /fixtures/odds (or /fixtures/odds/main for main lines only) to hydrate, then the odds channel for realtime updates.5
Run it in-play
scores and clocks for live state, plus bookmakers for suspension and staleness.6
Settle
GET /fixtures/settlement for per-outcome grades, final scores, and margins.Markets: address by coordinates, not by name
Every selection decomposes the same way on every bookmaker and every fixture:outcomeId, which means the same bet always resolves to the same marketId / outcomeId. Two rules matter when you build the offer:
- Each distinct line value is its own
marketId. Within onemarketIdthe outcomes are only the sides of that exact line. marketIdequals the market’s firstoutcomeId, andmarketLengthis the number of sides — together a complete probability space, which is what you need for margin application and completeness checks.
marketName / marketNameShort for display and marketId / outcomeId for logic. Full detail in Markets and outcomes and Market coverage.
Localization
All endpoints are prefixed with a language code (/en/…, /de/…, /fr/…), and the WebSocket takes lang at login. Translated fields — sportName, marketName, statusName, participant names — follow the prefix; identifiers never do. Build your UI on IDs and let names follow the user’s locale.
For crypto or multi-currency display, the currencies channel streams fiat and crypto rates against USD.
In-play
- Scores are per period, keyed
result,p1,p2, … —resultis the authoritative current score, period rows let you settle period markets. statusIdmoves forward only:0pregame →1live →2finished, or any state →3cancelled. Branch on the ID, not the name.clockscarriescurrentPeriod,currentTime,remainingTime, andstoppedfor live display and for holding bets during stoppages.- Suspension comes from the
bookmakerschannel (suspended,staleOdds) and frommarketActive/activeon the odds themselves. Wire all of them into one “can this be bet right now” decision.
p1 is a half in soccer, a quarter in NBA basketball, a set in tennis. expectedPeriods and periodLength on the fixture tell you which. The vocabulary is shared across all sports and is append-only; see Enumerations → period.
Settlement
GET /fixtures/settlement takes a fixtureId and optional outcomeId / playerId, and returns the fixture’s final state alongside per-outcome grades:
Grade on the selection key —
{fixtureId}:{outcomeId}:{playerId}, without the bookmaker — since a selection resolves identically regardless of who quoted it. Handle UNDECIDED and CANCELLED as explicit states in your settlement queue rather than retry-until-success.
Operating notes
- Snapshot, then stream, then re-snapshot on signal.
snapshot_requiredmeans your cursor left the replay window; it is a designed path, not an error. See Resume & Replay. - Filter at login.
sportIds,tournamentIds, andbookmakerscut message volume far more effectively than client-side filtering. - Use
sincefor backfills rather than full refetches, and key storage byoddsIdfor clean dedup. - Prefer
receiveType: "zstd"onoddsat scale (Compression). - New enum values are appended, never repurposed — ignore values you do not recognize instead of failing.
What you can rely on
- Markets are addressed, not matched.
marketType → period → handicap → sideresolves to the samemarketId/outcomeIdfor every bookmaker, so there is no per-book name-string matching layer for you to own and repair each time a book renames a market. - Lines never merge. Each distinct line value is its own
marketId, so “Over 2.5” and “Over 3.5” cannot collapse into one market and quietly mis-price your book. - The pipeline closes. The same
oddsIdaddresses the live price, its historical timeline, its closing line, and its settlement result — one key from pricing through to grading.