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.
Straight from the browser. A window longer than your access allows is trimmed rather than refused, and the response headers say so.
Or from the command line:
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_epl, soccer_fifa_world_cup, soccer_france_ligue_one, soccer_germany_bundesliga, soccer_italy_serie_a, soccer_spain_la_liga, soccer_uefa_champs_league, soccer_usa_mls, tennis_wta_guadalajara_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.
Free. Per-minute prices on the board instead of hourly, and the full 90 day export from this same URL. Your email is the key. Nothing is sent to it.
Want the morning email instead? That is The Odds Gap Daily, on the home page.
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 1am ET, and a game can appear at one line at one book and a different line at another. Nothing is backfilled or smoothed.
A second export covers player props: /api/props-export. Different shape from the file above, on purpose. Props are recorded at up to four fixed checkpoints per prop rather than on every scan: when we first see it, around six hours before the game, around one hour before, and at the close. The close is the last scan before the game starts, and props rescan every hour on the live board, so it lands inside that final window rather than at the literal last tick. Most vendors' closing lines work the same way; we would rather say it than let you assume otherwise. Each row carries the consensus fair probability (the median of every quoting book's de-vigged price, minimum three books), the best price on the board at that moment, which book had it, and how many books were quoting. There is no per-book ladder in it; the checkpoints are what we store.
Every row quotes the Over side: consensus_fair is the de-vigged probability of the Over in percent, and best_odds is the best Over price. The Under fair is 100 minus consensus_fair.
Touchdown scorer markets are Yes-only at the sportsbooks, so the Over is the Yes. First and Last Touchdown Scorer have one winner per game, so each sportsbook's full list is de-vigged together like a moneyline and the fair is the median across three or more sportsbooks. Anytime Touchdown Scorer can have several winners, so no book's list can be de-vigged on its own: consensus_fair is blank on those rows until three or more sportsbooks also post the No, and best_odds is still the best Yes price.
Pull a player's closing lines as CSV or JSON:
curl "https://theoddsgap.com/api/props-export?player=judge&anchor=close"
curl "https://theoddsgap.com/api/props-export?player=judge&market=batter_hits&anchor=close&format=json"
Every row also carries a player_id column (the last column in the CSV): the league and the name as the feed spells it, lowercased with spaces and punctuation turned into hyphens, so it stays the same on every pull. Pass it back to get exactly one player:
curl "https://theoddsgap.com/api/props-export?player_id=nfl:amon-ra-st-brown&anchor=close"
To find a player's player_id, search by name. Returns each match with the markets they appear in and their last game date:
curl "https://theoddsgap.com/api/props-export/players?sport=nfl&q=st.%20brown"
To see every market key we have captured, with a plain-English label, the sport, the row count and the first and last game date:
curl "https://theoddsgap.com/api/props-export/markets"
Name searches are case-insensitive substrings, with spaces URL-encoded and punctuation as the feed spells it, so st.%20brown finds Amon-Ra St. Brown and st%20brown does not. Rows captured before September 14, 2026 on a market two leagues share (NFL and college, NBA and WNBA) sometimes cannot be pinned to one league; their player_id starts with the sport instead, like football:, rather than a guess.
Parameters: player (name substring, case-insensitive), player_id (exact), market (exact market key, e.g. batter_hits), anchor (first_seen, t6, t1, close, or all), start and end (game dates), format (csv or json). Access tiers match the file above: recent days free with no signup, the full window with the free beta email.
Honesty notes: capture began in early August 2026, so history starts there, and the window rolls at 90 days. Only props quoted by three or more books have a consensus fair, so thin markets are absent by design. All rows postdate the August 12 exchange-price repair documented in the exchange price autopsy.
Three studies on this site were computed from this export and nothing else, so each one doubles as a worked example. All three publish their method, their caveats and their intervals, and the figures should reproduce if you rebuild them from the same rows.
devig_fair_prob rather than american_odds, because ten cents means something very different at -110 than at +400.commence_time and you can rebuild the staleness study, which found that measuring a book against its own closing price is close to useless because a book that never re-prices scores as one of the fastest. Measuring against the field at the same minute is the version that works.The whole section is at research, and every study links the exact slice of data it used.
Quoting any figure or finding published on this site is welcome, with attribution to The Odds Gap and a link to the page it came from. Our measurements, the matched-lines comparisons, the staleness and dispersion studies and the captured opening lines, are our own work and are licensed on that basis. The underlying odds are facts we aggregate from sources with their own terms. Bulk or automated reuse of the underlying data, rather than quoting a published figure, needs a conversation first: [email protected].
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: [email protected].
Live JSON instead of history: API docs.