Odds

Odds lines (market + model)

Time-series odds lines, newest first — the derived market line (`source: "eo_market"`) and the proprietary model line (`source: "eo_model"`; ADR 0009). With `?match={id}` the response is that match's line history, and `?cursor=` pages through it. **Without `?match=` the default is a bulk snapshot** — the latest line per source per open market across the game, the product's headline endpoint for pulling a whole slate in one call; the snapshot is a single page, so it **ignores `?cursor=`** (its `next_cursor` is always null). The movement fields (`open_price`, `delta_since_open`) are computed per response from the line's own series. Market rows appear once the multi-book scrape runs (`EXPOSE_MARKET_ODDS`; at least 2 contributing books per line); model rows only after the model's validation gate clears (`EXPOSE_MODEL_ODDS`) — before then model rows are simply absent, never faked. Raw per-book bookmaker rows are never returned (see the top-level description). **Markets & the `line` field.** Beyond match winner, the endpoint serves the derived line for additional markets as multi-book coverage arrives: `total_maps` (`outcome_key` `over`/`under`, `line` = the games threshold, e.g. `2.5`), `map_handicap` (`outcome_key` `home`/`away`, `line` = the **home team's signed handicap**, e.g. `-1.5`, carried by both complementary legs), and per-map `map_winner`. Because markets are distinguished by `line` as well as market and outcome, the **bulk snapshot may return more than one row per `market_id`** — one per distinct `line`. Each row is still the latest per `(market, outcome, line, source)`.

GET
/v1/{game}/odds

Time-series odds lines, newest first — the derived market line (source: "eo_market") and the proprietary model line (source: "eo_model"; ADR 0009). With ?match={id} the response is that match's line history, and ?cursor= pages through it. Without ?match= the default is a bulk snapshot — the latest line per source per open market across the game, the product's headline endpoint for pulling a whole slate in one call; the snapshot is a single page, so it ignores ?cursor= (its next_cursor is always null). The movement fields (open_price, delta_since_open) are computed per response from the line's own series. Market rows appear once the multi-book scrape runs (EXPOSE_MARKET_ODDS; at least 2 contributing books per line); model rows only after the model's validation gate clears (EXPOSE_MODEL_ODDS) — before then model rows are simply absent, never faked. Raw per-book bookmaker rows are never returned (see the top-level description).

Markets & the line field. Beyond match winner, the endpoint serves the derived line for additional markets as multi-book coverage arrives: total_maps (outcome_key over/under, line = the games threshold, e.g. 2.5), map_handicap (outcome_key home/away, line = the home team's signed handicap, e.g. -1.5, carried by both complementary legs), and per-map map_winner. Because markets are distinguished by line as well as market and outcome, the bulk snapshot may return more than one row per market_id — one per distinct line. Each row is still the latest per (market, outcome, line, source).

Authorization

AuthorizationBearer <token>

Primary auth (live). Authorization: Bearer <api-key> — the header takes precedence over the query fallback. The raw key is hashed (SHA-256, hex) and looked up in api.keys.key_hash; the raw value is never stored.

In: header

Path Parameters

game*string

Game slug. cs2 is the only populated title today; an un-onboarded game 404s cleanly.

Query Parameters

match?string

Scope to one match's full line history, newest first and cursor-paginated. Omit it for a different mode entirely: the bulk snapshot, which returns the latest line per outcome across every open market and is not paginated.

Formatuuid
source?string

Filter to one served source. Omit for both.

Value in

  • "eo_market"
  • "eo_model"
limit?integer

Page size — this endpoint's own default is 200 and its maximum 1000, higher than the API-wide 100/500, because an odds page is one row per outcome per source rather than one row per entity.

In history mode (?match=) this is a page size and cursor walks the rest. In snapshot mode (no match) it is a hard truncation: the snapshot is not paginated, meta.next_cursor is always null, and any lines past the limit are silently dropped. If meta.count equals your limit in snapshot mode, assume there were more.

Range1 <= value <= 1000
Default200
cursor?string

Opaque forward pagination cursor — pass the previous page's meta.next_cursor verbatim. Omit for the first page. Never construct one by hand.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/cs2/odds"
{  "data": [    {      "id": "019f2dc6-4539-7e15-bd2c-347d1562fd38",      "match_id": "019f28d9-f78f-790f-af0e-6d350172bc3e",      "tournament_id": null,      "market_id": "019f28da-10a5-744c-8281-6bc1f97f17d3",      "source": "eo_market",      "model_version": null,      "book_count": 2,      "outcome_key": "away",      "label": "DONSTU",      "participant_type": "team",      "participant_id": "019f23d2-5a34-7a73-b711-bd02601f9890",      "line": null,      "price": 13.39966832504146,      "is_winner": null,      "is_closing": false,      "open_price": 1.8144053351713343,      "delta_since_open": 11.585262989870126,      "captured_at": "2026-07-04T15:36:36.403882Z"    },    {      "id": "019f2dc6-4539-7958-ba0b-934cb420cb13",      "match_id": "019f28d9-f78f-790f-af0e-6d350172bc3e",      "tournament_id": null,      "market_id": "019f28da-10a5-744c-8281-6bc1f97f17d3",      "source": "eo_market",      "model_version": null,      "book_count": 2,      "outcome_key": "home",      "label": "SAW",      "participant_type": "team",      "participant_id": "019f23d2-5a33-70ad-a99f-3799b5cba292",      "line": null,      "price": 1.080647318443226,      "is_winner": null,      "is_closing": false,      "open_price": 2.22788979493807,      "delta_since_open": -1.147242476494844,      "captured_at": "2026-07-04T15:36:36.403882Z"    }  ],  "meta": {    "count": 2,    "next_cursor": null  }}
{  "error": {    "code": "not_found",    "message": "not found",    "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578"  }}
{  "error": {    "code": "not_found",    "message": "not found",    "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578"  }}
{  "error": {    "code": "not_found",    "message": "not found",    "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578"  }}
{  "error": {    "code": "not_found",    "message": "not found",    "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578"  }}