Skip to main content
Clients build entire betting products on OddsPapi, not just price displays. This guide walks the full pipeline — discovery, schedule, markets, prices, in-play, settlement — and names the endpoint or channel for each stage.
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:
That decomposition is baked into the 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 one marketId the outcomes are only the sides of that exact line.
  • marketId equals the market’s first outcomeId, and marketLength is the number of sides — together a complete probability space, which is what you need for margin application and completeness checks.
Use 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, … — result is the authoritative current score, period rows let you settle period markets.
  • statusId moves forward only: 0 pregame → 1 live → 2 finished, or any state → 3 cancelled. Branch on the ID, not the name.
  • clocks carries currentPeriod, currentTime, remainingTime, and stopped for live display and for holding bets during stoppages.
  • Suspension comes from the bookmakers channel (suspended, staleOdds) and from marketActive / active on the odds themselves. Wire all of them into one “can this be bet right now” decision.
Interpret periods against the sport’s structure — 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_required means your cursor left the replay window; it is a designed path, not an error. See Resume & Replay.
  • Filter at login. sportIds, tournamentIds, and bookmakers cut message volume far more effectively than client-side filtering.
  • Use since for backfills rather than full refetches, and key storage by oddsId for clean dedup.
  • Prefer receiveType: "zstd" on odds at scale (Compression).
  • New enum values are appended, never repurposed — ignore values you do not recognize instead of failing.
For pricing history, closing lines, and post-hoc analysis of your own book, see Historical odds and CLV.

What you can rely on

  • Markets are addressed, not matched. marketType → period → handicap → side resolves to the same marketId / outcomeId for 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 oddsId addresses the live price, its historical timeline, its closing line, and its settlement result — one key from pricing through to grading.