Skip to main content
We continuously improve the Odds API. This page lists new features, changes, fixes, and breaking changes.
All timestamps are UTC. If a change affects data shape or behavior, it will be marked as Breaking.

2026-10-01

Everything below about markets β€” the new marketType values, the renames, the period changes β€” is a data change only. No endpoint, field or type changed, and it all surfaces through GET /markets (and GET /fixtures/markets). Refetch the catalogue once on or after this date and you are current; odds payloads are untouched, they just start carrying the new outcomeIds.

✨ Added

  • GET /{lang}/fixtures/odds/parlay β€” price an accumulator from a list of oddsIds, across fixtures and sports. See Parlays & SGP.
  • GET /{lang}/fixtures/odds/sgp β€” price a correlated same-game parlay, quoted by the bookmaker. price carries the correlation, singlesPrice the naive product.
  • missingOddsIds on both new endpoints β€” names the requested legs that could not be found, so an empty section is never ambiguous.
  • X-API-Key header authentication on every endpoint, alongside the apiKey query parameter. Send one or the other. See Authentication.
  • 64 new esports marketType values and 568 new marketType Γ— period combinations β€” objectives, first-objective and multikill markets across Counter-Strike, League of Legends, Dota, Valorant and Rainbow Six. Map-level markets arrive under a new sportId 83 (ESport Mobile Legends).
  • 195 new period keys, all sub-period grids β€” p1r1 … p5r36 (round within map) and p1g2 … p5g6 (tennis). The vocabulary goes from 19 values to 213 and stays append-only.
Totals / spreads / team totals on esports objectives β€” totals-kills, totals-towers, totals-turrets, totals-dragons, totals-barons, totals-roshans, totals-inhibitors, totals-barracks, totals-rounds, totals-headshots, spreads-kills, spreads-towers, spreads-turrets, spreads-dragons, spreads-roshans, spreads-inhibitors, spreads-barracks, spreads-rounds, teamtotals-kills-team1/-team2, teamtotals-towers-team1/-team2, teamtotals-turrets-team1/-team2, teamtotals-dragons-team1/-team2, teamtotals-barons-team1/-team2, teamtotals-roshans-team1/-team2, teamtotals-inhibitors-team1/-team2, teamtotals-barracks-team1/-team2, teamtotals-rounds-team1/-team2First objective β€” firstblood, firsttower, firstbaron, firstroshan, firstinhibitor, firstbarracksMultikills β€” triplekill, quadrakill, pentakillOther β€” 1x2-kills, drawnobet-kills, oddeven-kills, oddeven-rounds, racetokills, winningmargin-rounds, playertotals-kills, playertotals-headshots, toqualifyRename targets that did not exist before β€” spreads-bookings, players-commitpenalty, players-goalieshutouts, players-goalsagainst, players-nextgoalscorer, players-powerplaypoints, players-secondgoalscorer, players-shorthandedgoals, players-shorthandedgoalscorer, players-thirdgoalscorer. These are new only because the market moved to them β€” see the rename table below.

πŸ” Changed

  • 24 marketType values are renamed for cross-sport consistency, affecting 222 markets in Ice Hockey, Soccer and Cricket. The singular prefixes player-, spread- and total- become the plural players-, spreads- and totals- already used everywhere else.
  • period changes on 74 markets. 28 move from fulltime to result across 26 sports that have no scoring phase after regulation, so the two values were names for one number β€” see Periods per sport. The other 46 had a blank period and are now populated. marketIds are unchanged throughout.
  • No market has an empty period any more. If you special-cased the blank, drop that branch.
fulltime β†’ result β€” the 1x2 market in 26 sports: MMA 203, Boxing 213, Beach Volley 303, Squash 343, Basketball 3x3 353, Curling 393, Padel 403, Soccer Specials 443, Beach Handball 473, Athletics 483, Badminton 493, Bowls 503, Cross-Country 513, ESport Call of Duty 563, ESport Overwatch 573, ESport Rainbow Six 583, ESport Rocket League 593, ESport StarCraft 603, ESport Valorant 613, ESport Arena of Valor 623, ESport King of Glory 633, Judo 643, ESport Honor of Kings 653, Speedway 663, Golf 673, Cycling 683.Boxing also moves two Total Rounds lines (216, 218) β€” its last fulltime markets, in a sport whose other Total Rounds lines were already on result.Blank β†’ populated, 46 markets:
13 of these renames merge into a marketType that already existed β€” players-anytimegoalscorer, players-assists, players-blocks, players-firstgoalscorer, players-goals, players-lastgoalscorer, players-points, players-saves, players-shots, players-shotsongoal, spreads-corners, totals-fours and totals-sixes were already in the registry alongside their singular twin. If you group by marketType, those groups get larger rather than disappearing β€” the duplicate spelling for the same concept is gone.The moneyline β†’ toqualify row is the one rename that is not cosmetic: a single Soccer market typed moneyline becomes toqualify, which is what it always meant. It is also the only market whose marketName changes in this release β€” Winner (incl. overtime) becomes To Qualify.
If you key markets on marketType Γ— period, re-pull the registry and regenerate those groupings. 296 markets change their marketType or period β€” a hard-coded or cached mapping will silently stop matching them.If you key on marketId, nothing breaks. No marketId was removed, and no market gained or lost an outcomeId; every one of the 32,950 existing ids still resolves, and the 13,891 additions are purely new.

2026-05-25

✨ Added

  • WebSocket receiveType: "zstd" β€” dictless compression. Opt-in zstd egress with no dictionary handling: every data frame is a standalone dictless zstd frame (dictId 0), decoded in one line (zstd.decompress(frame) β†’ JSON). ~5–6Γ— smaller than JSON on odds β€” the simplest way to cut bandwidth. See Compression.
  • WebSocket receiveType: "zstd-dict" β€” trained dictionaries. Maximum ratio (~7–9Γ— on odds) using per-channel dictionaries the server pushes as dict control frames at connect.

πŸ” Changed

  • receiveType: "zstd" now means dictless. During the zstd beta, "zstd" previously delivered trained dictionaries; that behavior moved to the new "zstd-dict". If you were decoding dictionary frames under "zstd", switch to "zstd-dict".
  • Dictionary version cache removed. The dicts login field is gone; the server now re-sends the (~32 KB) dictionaries on every zstd-dict connection, so clients no longer persist or version dictionaries across reconnects. A dicts field, if still sent, is ignored.

2026-04-09

✨ Added

  • Fixture view: venue section β€” new nested object on all fixture responses with venueId, venueName, and venueLocation. Translated per language.
  • Fixture view: clock section β€” new nested object on all fixture responses with currentPeriod, currentTime, remainingTime, remainingTimeInPeriod, and stopped. All keys present with null values until clock data is populated for a fixture.
  • Fixture view: participant1ShortName / participant2ShortName β€” new fields in the participants section of fixture responses, sourced from translated participant data.
  • Fixture view: seasonRound β€” new field in the season section of fixture responses.
  • Futures view: marketId β€” the market section in future responses now includes the marketId from the futures table. Name fields (marketName, marketType, playerMarket, participantMarket) remain null for now.
  • Participants endpoint: participantShortName β€” the GET /{lang}/participants response now includes participantShortName for each participant.
  • New REST endpoint: GET /{lang}/venues?venueIds=... β€” returns venue data with translated venueName and venueLocation.
  • New WebSocket channel: clocks β€” delivers live clock updates per fixture (same routing as scores: filtered by fixtureId, sport, tournament). Supports resume/replay.

⚠️ Breaking

  • Fixture response shape changed β€” all fixture endpoints (REST and WebSocket) now include three new top-level keys: venue (object), clock (object), and updated participants / season sections. Clients parsing fixture responses strictly should update their models.
    • season now includes seasonRound: integer | null
    • participants now includes participant1ShortName: string | null and participant2ShortName: string | null
    • venue: { venueId, venueName, venueLocation } added after season
    • clock: { currentPeriod, currentTime, remainingTime, remainingTimeInPeriod, stopped } added after scores
  • Future response shape changed β€” market.marketId is now populated (integer or null) instead of always null.

2025-12-12

✨ Added

  • WebSocket resume & replay support using entryId cursors
  • New WebSocket channels:
    • injuries
    • lineups
    • stats
  • AsyncAPI 3.0 reference for WebSocket gateway

πŸ”§ Improved

  • Reduced WebSocket latency for odds and scores
  • Better filtering for sportIds, tournamentIds, and bookmakers

πŸ› Fixed

  • Fixed an issue where some odds updates were delivered without bookmaker gating
  • Fixed incorrect live flag on some fixtures during transitions

2025-11-28

⚠️ Breaking

  • odds.payload.odds keys are now always bookmaker-scoped
    • Old clients expecting a flat structure must update

✨ Added

  • Support for receiveType: "binary" (MessagePack)
  • Added entryId to all update messages

2025-11-10

✨ Added

  • Initial WebSocket gateway
  • Channels:
    • fixtures
    • scores
    • odds
    • bookmakers