Get Historical Closing Odds
Historical closing lines: game-line h2h/spreads/totals plus player props. 10 credits.
Game lines come from the historical_odds archive (1.3M+ rows across 267 sport keys, sources include Pinnacle, bet365, Betway, William Hill, Interwetten, Ladbrokes, BetVictor, betfair_exchange).
Player props come from prop_closing_lines (15.2M+ rows across 993 sport keys, all standard player markets). Use markets=player_strikeouts (or any other player_* key) to pull these. The player= param filters to a specific player by substring.
Pass include_imports=true to also union your own customer-imported rows from POST /v1/historical/closing-lines/import (cost: 0 extra credits).
ROW CAP AND ORDERING (contract): every leg of the answer is returned NEWEST GAME_DATE FIRST under a hard row cap, so when a request matches more rows than its cap the OLDEST rows are the ones dropped, never the most recent. The two PUBLIC legs (game lines, props) are capped at x-archive-row-cap each; the include_imports leg is your own upload, scoped to your API key, and carries a separate, larger 10,000-row cap that x-archive-row-cap does NOT describe.
x-archive-truncated is false, or a comma-separated list of the public legs that hit their cap (game_lines, props). The imports leg is never named there. When a leg is clipped the response also carries x-archive-oldest-game-date: the exact value to send back as dateTo to continue reading older rows without skipping any.
PAGING: limit + offset, or dateTo. limit and offset apply to each PUBLIC leg independently and are the reliable way to read a match set bigger than one page: walking offset 0, limit, 2*limit, ... returns every matching row exactly once, because both public legs are ordered on a key that is unique within the leg (props: the seven-column natural key the dedupe is built on; game lines: game_date plus the row id). Omit both and you get exactly the pre-paging behaviour: one page of x-archive-row-cap rows per public leg. The response echoes what it served as x-archive-limit / x-archive-offset, and a clipped page carries x-archive-next-offset, the value to send back.
THE include_imports LEG IS SERVED ONLY ON offset=0. It is your own upload under its own larger cap, not part of the paged archive read, so re-sending it on every page would duplicate every imported row across your pages. Page 1 carries it in full; later pages carry archive rows only.
A dateTo WALK IS STILL SUPPORTED AND IS CHEAPER OVER LONG RANGES, but it TERMINATES ONLY WHEN THE DATE MOVES: dateTo cannot advance when a single game_date fills the whole cap on its own (measured 2026-08-08: soccer_uefa_conference_league with a game-level market named returns 5,000 rows that are all game_date 2026-08-06, a day that holds 6,983). In that case x-archive-oldest-game-date equals the newest date you received, the response says so in x-archive-truncated-hint, and re-requesting with that dateTo returns the identical page for another 10 credits. Use offset= to read past it, or narrow with markets=, bookmakers= or player=. Clients that loop on dates should stop when x-archive-oldest-game-date stops decreasing.
THE CAP IS SHARED ACROSS BOOKS, so a dense book can crowd a sparse one off the page even when the date cursor advances normally. Pass bookmakers= when you only need one book's closing line. Measured 2026-08-08 on soccer_uefa_conference_league_qualifiers with markets=moneyline,correct_score,corners,double_chance: the answer is 4,940 tenbet rows and 60 pinnacle rows, and the pinnacle rows older than 2026-08-04 sit behind the cursor rather than in the first page. bookmakers=pinnacle returns all 256 of them in one call.
Examples:
- GET /v1/historical/sports/baseball_mlb/closing-odds?markets=player_strikeouts&date=2025-08-15&player=Skenes
- GET /v1/historical/sports/soccer_epl/closing-odds?bookmakers=pinnacle&season=2023-24
- GET /v1/historical/sports/basketball_nba/closing-odds?markets=h2h,player_points&dateFrom=2024-12-01&dateTo=2024-12-31&include_imports=true
- GET /v1/historical/sports/soccer_uefa_conference_league/closing-odds?markets=player_shots_on_goal&date=2026-08-06&limit=5000&offset=5000 (second page of a day whose props overflow one page)
Request
- Base URL: https://parlay-api.com
- URL: https://parlay-api.com/v1/historical/sports/{sport_key}/closing-odds
- Auth: one of:
- API key in header X-API-Key
- API key in query parameter apiKey
- HTTP bearer
Path parameters
Query parameters
Comma-separated. Game lines: h2h, spreads, totals. Player props: player_strikeouts, player_total_bases, player_points, player_rebounds, player_assists, player_pass_yds, player_rush_yds, player_shots_on_goal, etc. (any market_key from prop_closing_lines). Mix freely: markets=h2h,player_strikeouts.
Comma-separated. Game lines: h2h, spreads, totals. Player props: player_strikeouts, player_total_bases, player_points, player_rebounds, player_assists, player_pass_yds, player_rush_yds, player_shots_on_goal, etc. (any market_key from prop_closing_lines). Mix freely: markets=h2h,player_strikeouts. Repeating this parameter is the same as the comma form: ?markets=h2h&markets=spreads and ?markets=h2h,spreads are one request, billed identically, and return the union. A value repeated across occurrences is counted once.
Comma-separated. Game-line queries default to pinnacle. Prop-only queries default to all tracked books.
Comma-separated. Game-line queries default to pinnacle. Prop-only queries default to all tracked books. Repeating this parameter is the same as the comma form: ?markets=h2h&markets=spreads and ?markets=h2h,spreads are one request, billed identically, and return the union. A value repeated across occurrences is counted once.
Season filter for game lines (e.g. 2023-24)
Specific date YYYY-MM-DD (shortcut for dateFrom=dateTo=date)
Start date (YYYY-MM-DD)
End date (YYYY-MM-DD)
Filter props to a specific player name (substring match)
Also include rows you've imported via POST /v1/historical/closing-lines/import
Rows per PUBLIC leg (game lines, props) for this page, 1..5000. Omit for the full row cap, which is exactly the behaviour this endpoint had before paging existed.
Rows to skip in each PUBLIC leg. Use with the same limit to read past the row cap, including the case where one game_date fills a whole page and dateTo paging cannot advance. Both public legs are ordered on a unique key, so offset paging neither skips nor repeats rows.
Response
Successful Response
Changes
No recorded changes to this operation across all 1 revision of this API.