Changelog
The API is live at /v1. This page records API changes and the policy that governs them.
Initial release: /v1 is live
Section titled “Initial release: /v1 is live”The API serves sports, bookmaker and market catalogues, upcoming and in-play odds, player props, and recorded history. Start with the quickstart.
2026-10-21: /v1/markets?sport= lists one sport’s books
Section titled “2026-10-21: /v1/markets?sport= lists one sport’s books”GET /v1/markets takes an optional sport (nfl, soccer, epl, tennis, …). With it,
the list holds only that sport’s markets, each entry’s bookmakers names only the books that
carry the market for that sport, and sports is that one sport. A soccer league key answers
as soccer, a tennis tournament key as tennis; a key that is not a sport key returns 404 UNKNOWN_SPORT.
Without sport nothing changes: bookmakers is every book that carries the market in any of
its sports.
Also in this release: Pinnacle is no longer listed for soccer btts or corners_total; it does not
offer them.
2026-10-14: league on soccer fixtures, tournament on tennis
Section titled “2026-10-14: league on soccer fixtures, tournament on tennis”Soccer fixtures carry league: {key, title} (for example {"key": "epl", ...}, the key
soccer?league= takes). Tennis fixtures now carry the same object as tournament, the key
tennis?tournament= takes, instead of league. Other sports carry neither field: their sport
key is already the league. Live, history, prop history and websocket bodies all follow this;
event ids do not change.
2026-10-14: props carry one player name, a player_id and main
Section titled “2026-10-14: props carry one player name, a player_id and main”Every row on /props, /props/live and a single event’s props now names its player one way
across all books of the fixture: the spelling the big US books use, where before each book kept
its own (A.J. Barner, AJ Barner and Aj Barner on one game). A team defense is one player
per team (SEA D/ST). Each row also carries player_id, a fixed id such as
nfl:jaxonsmithnjigba that is the same on every book; join on it rather than on
the name. And each row carries main: true | false: exactly one row per bookmaker, player and
stat is that book’s main line, and it comes first among that player’s lines for the stat. The
main line is the one priced on both sides with the most even prices; a line priced on one side
only (a milestone such as Over 249.5) is main only when the book prices no line on both sides.
2026-10-14: history series starts full, then sends changed outcomes
Section titled “2026-10-14: history series starts full, then sends changed outcomes”For fixtures with archived change rows, each bookmaker and market’s first series point contains
its full market. Later points contain only outcomes whose price, point or size changed, with
their own values and recorded_at. Apply points in order to rebuild the market. A since-bounded
request starts full at the first emitted time, seeded from earlier changes. Fixtures without
change rows retain whole-market checkpoint points. Opening and closing routes are unchanged.
See the history guide.
2026-10-14: main lines first, with an explicit flag
Section titled “2026-10-14: main lines first, with an explicit flag”Every spread, total and team-total ladder now puts its main line first across upcoming
and live odds, one fixture, the live feed, and opening and closing history.
Series points keep recorded order and omit main flags while they represent partial timestamp batches.
Each outcome on these main-first ladders adds main: true|false. The book’s featured two-sided line takes
priority; otherwise the most balanced two-sided line by implied probability is main.
Lines with an implied probability sum at or below 1.25 take priority over lines above 1.25.
A one-sided line is main only if there is no two-sided line. Extreme exchange and
prediction-market quotes remain as quoted, including single-line moneylines.
Historical team totals now return separate market objects for each team, named by each
outcome’s description; quotes without a recorded team name remain available.
2026-10-07: every list splits into upcoming and live
Section titled “2026-10-07: every list splits into upcoming and live”/v1/sports/{sport}/odds, /events and /props now return only fixtures that have not
started, on every plan. A fixture leaves them at kickoff. Three new routes return only fixtures
in play now (started and not finished): /v1/sports/{sport}/odds/live, /events/live and
/props/live. They take the same selectors and formats, need in-play odds (Growth and up) and
are refused on Free and Starter with the same PLAN_REQUIRED answer as a started fixture asked
for by id. They do not need the live feed add-on. Aggregate soccer and tennis lists still
carry every upcoming fixture, with no date cap. Single-event and historical routes are unchanged.
2026-09-30: every fixture carries is_live
Section titled “2026-09-30: every fixture carries is_live”Every fixture object now has "is_live": true | false right after commence_time, on
/events, /odds, a single event’s odds, /props, the historical routes and the
live feed. It is true from kickoff until the game is over
(each sport has its own cut-off after kickoff) and false before and after, so you no longer
compare commence_time with your own clock. It is worked out when the response is served, so it
flips at kickoff even while prices are unchanged. On the live feed a flip arrives as one compact
status upsert (event_id, is_live) and moves no price.
2026-09-28: the live feed sends a price only when it moves
Section titled “2026-09-28: the live feed sends a price only when it moves”A changes message on the live feed now sends an outcome upsert
only when something on that outcome actually moved. When a book re-confirms a market and no
price in it moved, you get one small unchanged upsert for the market (event_id,
bookmaker, market, last_update) instead of every price again: set that market’s
last_update and keep its prices. Measured on our soccer feed, 99.5% of re-confirmed prices
had not moved, so this cuts a busy subscription’s traffic many times over while every price
still carries proof of when the book last confirmed it; see
only what moved.
2026-09-28: a live feed picture or changes message can arrive in parts
Section titled “2026-09-28: a live feed picture or changes message can arrive in parts”A picture or changes message on the live feed now carries part
and parts. Most of the time both are 1. A message too big for one WebSocket frame (a busy
sport’s default picture can run several megabytes) now arrives as several consecutive frames
of the same type instead of one oversized frame. Every part shares the same cursor and
resume_token, in order, never split mid-fixture or mid-entry. Reassemble by concatenating
data (or upserts/removals) across parts and treat the message complete once
part == parts; see part and parts. Keep a
resume_token only from a complete message: if the connection drops between parts, discard
the partial message and resume with the token of the last complete one.
2026-09-28: outcomes are named after the fixture’s teams, away first
Section titled “2026-09-28: outcomes are named after the fixture’s teams, away first”On h2h and spreads (every period), each team outcome’s name is now exactly the
fixture’s own away_team or home_team, whatever spelling the book itself uses (a book’s
PHI Eagles is served as Philadelphia Eagles). Outcomes come in a fixed order: the away
team, then the home team, then Draw on a three-way moneyline, rung by rung on a ladder. A
team_totals outcome’s description names the fixture’s team the same way, and totals are
always Over then Under.
2026-09-28: the period is a field, not a key suffix
Section titled “2026-09-28: the period is a field, not a key suffix”A market’s key is now its family alone (h2h, spreads, totals, team_totals, …),
never a period suffix. A period market instead carries a separate period field (1h, 2h,
1q..4q, 1p..3p, f5, 1i, 1s..5s, reg); a full-game market has no period field
at all. Select periods with the new periods request parameter: omit it for the full game
only, name periods to get just those (periods=1h), add full to keep the full game beside
others (periods=full,1h), or ask for everything (periods=all). The same rule now applies to
player props (stat is the stem alone, period moves to period), to the history endpoints,
and to /v1/markets (the family field is gone since it always equalled key; one row per
key and period). Old suffixed keys such as totals_f5 now return 422 INVALID_MARKET.
The policy going forward
Section titled “The policy going forward”Within /v1, only additive changes ship without notice: a new endpoint, a new optional
parameter, a new response field, or a new value in a field already marked
x-extensible-enum (a market key, an error code, a plan). Renaming or removing a field,
changing its type, or changing what a parameter defaults to never ships inside /v1. That kind
of change ships as /v2 instead, with /v1 kept running and both versions documented for a
minimum 90-day notice period.
Accepted values and optional fields
Section titled “Accepted values and optional fields”Adding an accepted request value, making a required parameter optional, adding a response header, or unlocking an operation for another plan is additive. Narrowing accepted request values, changing a field’s meaning, or changing behavior when a parameter is omitted requires a new API version. Response value lists may grow; clients should accept unfamiliar values. The published API reference defines the fields covered by this policy.
Deprecation and migration
Section titled “Deprecation and migration”A new version is announced here and in the documentation at least 90 days before /v1
stops answering. Both versions remain documented and callable throughout that period.
/v1 responses carry a Deprecation header (RFC 9745) from the announcement and a Sunset
header (RFC 8594) giving its retirement date. Migration notes explain what changed and how
to move. During the notice period, /v1 keeps its existing behavior and access rules.