Every price this site has scanned, as a plain CSV. One row per snapshot, book, market and side, with the de-vigged fair probability and a flag marking who had the best price at that moment. No API key, no signup for the last 7 days.
raw_snapshots table the Line Shop, the closing-line math, and the book comparison all read from. It is the site's own source data, not a summary of it. Prediction-market prices are fee-adjusted, so an exchange price in this file is what a taker actually pays, not the raw ask.One request, one CSV. It streams, so a long window starts downloading immediately instead of waiting on the server to build the whole thing.
curl -o mlb.csv "https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb"
Last seven days of MLB, every market. To narrow it down:
curl -o mlb-ml.csv "https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb&market=ml&start=2026-07-25&end=2026-08-01"
Straight into pandas, if that is where it is going:
import pandas as pd
df = pd.read_csv("https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb&market=ml")
Long (tidy) format. Long is the modeling standard, and a wide layout with a column per book breaks every time a book is added or removed. Need wide? Pivot on book, or ask us and we will add it.
| Column | Meaning |
|---|---|
snapshot_ts | UTC ISO timestamp of the scan that captured this price. |
sport | Sport key, e.g. baseball_mlb, basketball_nba. |
away, home | Team names as the odds feed supplies them. |
commence_time | UTC ISO scheduled start. Rows where this is later than snapshot_ts are pre-game. |
market | ml, spread, or total. |
side | home / away / draw for moneyline, home / away for spread, over / under for totals. |
line | The spread or total number. Blank on moneyline rows. |
book | Book key, e.g. draftkings, pinnacle, kalshi. |
american_odds | Executable American odds. Exchange taker fees are already applied, so this compares directly to a sportsbook price. |
devig_fair_prob | Fair probability from 0 to 1 (not a percentage), from de-vigging this book's own two sides with the power method. Soccer moneylines are normalized across all three outcomes. Blank when the book posted only one side of the market, because there is no vig to strip and we will not invent a number. |
best_price_flag | 1 if this book tied or beat every other book on the same market, side and line at that snapshot. Ties all get a 1. |
1. If you are ranking books, group by (market, side, line) and require more than one book in the group.| Param | Meaning |
|---|---|
sport | Required. One sport key, tennis for every rotating tennis key, or all. Keys: americanfootball_ncaaf, americanfootball_nfl, baseball_mlb, basketball_nba, basketball_ncaab, basketball_wnba, icehockey_nhl, mma_mixed_martial_arts, soccer_fifa_world_cup, soccer_uefa_champs_league, soccer_usa_mls, tennis_atp_canadian_open, tennis_atp_washington_open, tennis_wta_canadian_open. |
start | YYYY-MM-DD or a full ISO timestamp. Defaults to the start of your window. |
end | YYYY-MM-DD or a full ISO timestamp. Defaults to now. |
market | ml, spread, total, a comma-separated list, or all (default). |
format | long. The only value in v1. |
Response headers carry the window that was actually served: X-Window-Start, X-Window-End, X-Access-Tier, and X-Window-Clamped when a requested start was older than your window allows. Very large pulls are capped, and X-Next-Start hands back the timestamp to resume from.
The beta is free as well, it just wants an email. Drop it here and the same URL starts returning 90 days.
Snapshots roll off after 90 days, so this window is everything there is. Openers and closing lines are captured separately and survive the rollover.
Prices are captured on every scan across the books we cover, stored raw, and served back unchanged apart from the exchange fee adjustment. The de-vig, the fee model, and the line-selection rules are all written out on the methodology page, including why the power method is used instead of simple multiplicative scaling.
Coverage gaps are real and we would rather you knew: a book that was not returning a price at a given scan simply has no row, scanning runs 7am to 9pm ET, and a game can appear at one line at one book and a different line at another. Nothing is backfilled or smoothed.
Free for research, modeling, and writing, with attribution to The Odds Gap and a link to theoddsgap.com. Not permitted: reselling the data, repackaging it as your own feed or product, or sustained bulk scraping (rate limits are enforced). Portions arrive through licensed feeds, so this exists for people who want to study the market, not as a data source for another product. Heavier or commercial use: admin@theoddsgap.com.
Live JSON instead of history: API docs.