# PropLine > Real-time player props and game odds REST API for sports bettors and developers. The-odds-api compatible response format. Adds prop resolution against actual box scores, cross-book +EV calculator, and unlimited historical depth — features no other odds API offers. Last updated: 2026-10-22. Tested with Cursor, Claude Code, ChatGPT, GitHub Copilot, Continue.dev. Designed to be pasted directly into any LLM context window. PropLine returns betting odds from 116 books — 101 sportsbooks (BetMGM, Bovada, Betway, Courtside, Sportzino, Heritage Sports, Jazz Sports, YouWager, Thrillzz, Eurobet, AdmiralBet, Snai, Winamax, Betclic, PMU, Genybet, Ladbrokes, Tipico, Merkurbets, Codere, TonyBet, Bet99, Paddy Power, LiveScore Bet, Strendus, Wplay, Codere MX, Placard, Solverde, Sportium, Marca Apuestas, Betclic PT, Danske Spil, Veikkaus, Sazka, Pame Stoixima, Bet25, Norsk Tipping, TOTO, Ladbrokes BE, Superbet RO, Napoleon Games, Superbet PL, Stoiximan, STS, Synot Tip, Ladbrokes AU, PlayUp, bet-at-home, Fortuna CZ, Fortuna PL, AdmiralBet DE, Star Sports, LV BET, Totalbet, Palmerbet, Betr AU, NetBet RO, Novibet, theScore Bet, PlayAlberta, TopSport, OlyBet, SuperSport, MaxBet, Soccerbet, MerkurXtip, PSK, SportyBet NG, PlayNow, Mise-o-jeu, Jouez Sport, Mozzart Bet, Germania Sport, Meridianbet, Sportna loterija, Te Apuesto, Bet9ja, Betika, SportPesa, Tippmix, tipp3, Supabets, Betway ZA, Hollywoodbets, FanDuel, DraftKings, Fanatics, Fliff, Hard Rock Bet, Pinnacle, BetRivers, Unibet, 1xBet, TAB AU, ReBet, BetUS, BetOnline.ag, LowVig.ag, SBOBET, BookMaker.eu) + 6 DFS sites (PrizePicks, Underdog Fantasy, Sleeper, Dabble, ParlayPlay, DraftKings Pick6) + 3 prediction markets (Kalshi, Polymarket, Polymarket US) + 6 betting exchanges (Matchbook, Smarkets, Novig, ProphetX, SX Bet, Betfair Exchange) — for MLB, NBA, WNBA, NHL, NFL, NCAAF, NCAAB, soccer (28 leagues incl. FIFA World Cup), tennis, golf, UFC, boxing, cricket, darts, table tennis, snooker, esports (LoL/CS2/Valorant incl. Counter-Strike player props), rugby, AFL, volleyball, badminton, cycling (Tour de France outrights), CFL, and NBA Summer League. Real-time push ingest from five books (DraftKings, FanDuel, Fanatics, Kalshi, Polymarket — a line move lands in about a second, measured p50 0.1–1.1s / p90 ≤2s in play); the other 112 books are polled at ~30-45s in play, ~60-90s pre-match. Updated 24/7. Paid tiers start at Hobby ($9/mo), the cheapest API in the market that includes both player props AND prop resolution. Webhook push subscriptions from Streaming Lite ($39/mo) for line-movement and resolution events. NBA/WNBA first-score markets: `player_first_basket` + `team_first_basket` (first points of the game, free throws count — FanDuel, DraftKings, Hard Rock) and `player_first_field_goal` + `team_first_field_goal` (first made field goal, free throws excluded — Fanatics, DraftKings), plus per-team first scorer: `team_first_basket_scorer` (FanDuel, free throws count) and `team_first_field_goal_scorer` (DraftKings, Fanatics, free throws excluded) — one market per team, team in the description ("First Field Goal Scorer - Golden State Warriors"), outcome `name` = player. All graded from the league play-by-play. Kalshi coverage (`bookmakers=kalshi`) goes beyond game lines: NFL team totals (full game and 1st half), winning margin and half-time/full-time (NFL + NCAAF), NFL/MLB/WNBA player props, La Liga + EPL total and team corners (`total_corners`, `team_corners`), La Liga anytime/first goalscorer, WTA 125 / ATP Challenger / ITF match winners, UFC fight goes the distance (`fight_distance`), and golf winner, make-cut and top 5/10/20 on the PGA Tour and DP World Tour. Base URL: `https://api.prop-line.com`. Auth via `apiKey` query param or `X-API-Key` header. Free tier (1,000 req/day) requires only an email signup at https://prop-line.com. ## When to use PropLine Reach for this API when the question is: what are the odds on this game or player right now (across every book at once); did that player prop hit, and what was the actual stat; how often does this player go over their line; which book pays the most on a given bet; is this price +EV against a no-vig fair line; how did this line move from open to close. Full agent instructions, including when NOT to use it and how to call it efficiently: https://prop-line.com/agent-instructions.md (also at /AGENTS.md). Do not use PropLine to place a bet (it publishes market data, accepts no wagers, carries no affiliate links), for betting advice or profit claims (+EV is analysis, not a prediction), for play-by-play (box-score stats refresh ~90s, there is no per-play stream), or for non-sports prediction markets. Calling it well: pass `markets=` on every odds call; discover with GET /v1/sports -> /events -> /events/{id}/markets before pulling a full board; key on `id`, never on team names; self-throttle on the `RateLimit-Limit` / `RateLimit-Remaining` / `RateLimit-Reset` response headers and honour `Retry-After` on a 429; keep at most 20 requests in flight per key (8-10 is the recommended fan-out) or you get a 503 with `Retry-After: 1`, and prefer bulk `/v1/sports/{sport}/odds?markets=` over one call per event; ignore unknown fields, since new books and markets land inside /v1 continuously (versioning policy: https://prop-line.com/api-versioning). DFS prices (PrizePicks / Underdog / Sleeper / Dabble / ParlayPlay / DraftKings Pick6) are pick'em entry prices, not two-way odds — they are excluded from /ev and /best-line, so do not compare them against a sportsbook price. ## Reference - [Developer resources](https://prop-line.com/developers): every machine-readable entry point in one place — REST reference, OpenAPI spec, SDKs, CLI, MCP server, webhooks - [Agent instructions](https://prop-line.com/agent-instructions.md): when to use PropLine, when not to, and how to call it efficiently (also at /AGENTS.md and /.well-known/agents.md) - [OpenAPI 3.1 spec](https://prop-line.com/openapi.json): machine-readable description of the whole API surface - [Versioning & deprecation policy](https://prop-line.com/api-versioning): what changes inside /v1, and the 12-month sunset window signalled by Deprecation + Sunset headers - [About](https://prop-line.com/about) / [Contact](https://prop-line.com/contact): who runs PropLine, how the data is produced, and how to reach a human (support@prop-line.com) - [API documentation](https://prop-line.com/docs): Full endpoint reference, response schemas, authentication, rate limits, market keys, sport keys - [llms-full.txt](https://prop-line.com/llms-full.txt): Complete docs inlined as a single file — fetch this one URL to give an LLM everything needed to write working PropLine code - [Pricing](https://prop-line.com/pricing): Free (1,000 req/day) / Hobby $9 (5,000) / Pro $19 (25,000) / Streaming Lite $39 (250,000) / Streaming $79 (1,000,000) / Enterprise (unlimited) — every tier gets the same data freshness — no latency gating (five books stream in real time at ~1s — DraftKings, FanDuel, Fanatics, Kalshi, Polymarket; the other 22 refresh on a ~30-45s cycle per book in play, ~60-90s pre-match) - [Historical Backfill](https://prop-line.com/historical-backfill): $99 one-time, no subscription — 7-day full-archive pull on any tier (trailing 2-year lookback, uncapped export calls) and the only access to `/v1/exports/odds-history`, the raw tick-by-tick line-movement firehose. For backtesters and CLV studies that want the dataset, not a monthly plan - [Live +EV plays](https://prop-line.com/ev): Cross-book +EV opportunities with no-vig fair lines anchored on Pinnacle, refreshed every 60s - [Freshness](https://prop-line.com/freshness): Live per-bookmaker staleness across all 116 books — auto-refreshes every 5s, no auth required - [Status](https://prop-line.com/status): Live API uptime and incident history, public on every tier including free. UptimeRobot polls `api.prop-line.com/health` every 5 minutes from infrastructure independent of ours. Published uptime is not an SLA — a contractual guarantee with a financial remedy is an Enterprise term - [Today's resolved props](https://prop-line.com/today): Player props graded against actual box scores, broken down by sport and market - [Odds API by market](https://prop-line.com/odds-api): One page per (sport, market) — what the market is, which books post it right now, a live sample response, a working curl, and recently SETTLED outcomes with the actual stat each was graded against. Generated from live data, so a market with no live board and no graded results has no page ## Endpoints - [GET /v1/sports](https://api.prop-line.com/v1/sports?apiKey=99c1393f8c921749d193f87b3ef688c5): list active sports - the-odds-api sport key names work as aliases (`americanfootball_nfl` -> `football_nfl`, `icehockey_nhl` -> `hockey_nhl`, `soccer_spain_la_liga` -> `soccer_la_liga`, ...). Only where the competition is identical; otherwise a structured 404 with `did_you_mean` (e.g. `tennis_atp` has no equivalent — our `tennis` spans ATP + WTA + ITF; filter on each event's `tour`). Canonical list: GET /v1/sports - [GET /v1/sports/{sport_key}/events](https://api.prop-line.com/v1/sports/baseball_mlb/events?apiKey=99c1393f8c921749d193f87b3ef688c5): upcoming events for a sport - [GET /v1/sports/{sport_key}/odds](https://api.prop-line.com/v1/sports/baseball_mlb/odds?apiKey=99c1393f8c921749d193f87b3ef688c5&markets=h2h,spreads,totals): bulk game-line odds for all upcoming events. Optional `bookmakers=` filter (comma-separated book keys, same param name as the-odds-api; also on per-event /odds, /odds/history, /odds/closing, /movement). Optional `includeLinks=true` (also on per-event /odds + /best-line) adds a per-book `link` — the book's public event-page URL for click-out (Bovada/DraftKings/FanDuel/BetMGM/Kalshi/Polymarket/Smarkets/ProphetX/Novig/DraftKings Pick6; others null) — plus `app_link`, a mobile app-open deep link (ProphetX only today, null elsewhere). Optional `includeBookIds=true` (also on per-event /odds) adds each book's OWN ids — `book_event_id` per bookmaker block and `book_outcome_id` per outcome — for joining onto a book's native feed by id instead of fuzzy-matching names and lines. Optional `max_age=N` (seconds, also on per-event /odds) drops markets not delivered in the last N seconds. Books with no in-game feed are left out of games in progress unless `includePregameOnly=true` (DFS books always stay). PrizePicks over-only projections omit the Under unless `includeRestricted=true` (both /odds endpoints), which serves it and adds `allowed_wager_types` (`over` / `under_or_over`, PrizePicks' own value) per PrizePicks outcome. Optional `includeDepth=true` (also on per-event /odds) adds `depth` per outcome — up to three order-book levels BEYOND the served price, best-first, each `{price, size}` (American odds; dollars a taker can spend at that level) — populated for ProphetX, Polymarket and Polymarket US, `[]` elsewhere, omitted unless requested. Kalshi ships its event ticker plus the per-contract market ticker (e.g. KXMLBGAME-26AUG08NYYBOS-NYY); PrizePicks ships its game id plus the per-outcome projection id, which is the token a populated entry URL is built from (app.prizepicks.com/board?projections={book_outcome_id}-o-{point}); Underdog, Sleeper, Dabble and Novig ship per-outcome ids too. NB whether the two legs of a market SHARE one id varies by book — Kalshi and PrizePicks share it (one binary contract / one projection, direction chosen separately), Underdog/Sleeper/Dabble/Novig give each leg its own — so group a pair by (market, player, point), never by id. Each market carries a `team` field — the canonical event team name when the market is scoped to one team (a TEAM total), null for the game total. Both ride the same `totals` key, so `team` is what tells them apart (`"Total"` 2.5 with team=null vs `"Team Total - Arsenal"` 1.5 with team="Arsenal"); it is always null outside `totals`. Each market also carries `line_type` — `main`, `alternate` or `milestone` (an N+ rung): among one book's rows of a line market for one player or team exactly one is main (the book's own primary row where it labels one, else the most balanced pair); every Kalshi / Polymarket US outcome also carries its own `line_type`, because those books put several players on one row. Also on /odds/history, /odds/closing and /best-line price rows. The book's own `description` is still there as the human-readable label - [GET /v1/sports/{sport_key}/events/{event_id}/odds](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/odds?apiKey=99c1393f8c921749d193f87b3ef688c5&markets=batter_hits,pitcher_strikeouts): full player props for one event (the money endpoint). Underdog Fantasy outcomes carry a `payout_multiplier` (DFS boost/discount factor, populated on every Underdog outcome; 1.0 = standard pick, e.g. 1.5 = boost, 0.75 = discount; null = not Underdog) — keep only `payout_multiplier == 1.0` when comparing DFS lines to sportsbook consensus. PrizePicks outcomes carry `dfs_odds_type` instead (`standard` = the market line, `goblin` = easier/lower-payout, `demon` = harder/higher-payout; null for sportsbooks) — filter to `standard` for the market line; goblin/demon arrive as their own per-line markets. `dfs_odds_type` is also present on /results, /odds/history, /odds/closing and /movement (same semantics). PrizePicks goblin/demon outcomes also carry `line_gap` on /odds — the signed delta from that player+stat's standard line (`point - standard_point`; +demon harder / -goblin easier; null when no standard counterpart on the slate). PrizePicks publishes no numeric per-pick multiplier, so flavor + line_gap are the modelable signals for fitting per-pick payouts. The-odds-api does not expose DFS multipliers. Exchange outcomes (ProphetX + Novig) and Pinnacle carry `liquidity` — dollars actually bettable at the quoted price (Pinnacle: its posted max risk stake on the market; null for books without a resting-size/limit signal; Novig's is the resting depth behind the takeable price, re-read from its live order book every cycle on game lines; Novig player props are read from its public order book on a rotating budget (games within 2 hours re-read about every 15 minutes, later and in-play games about every 45), and carry null when that book is older than 60 minutes or no longer matches the price); filter small values before treating an exchange price as bettable, and `liquidity_updated_at` — the exchange's own timestamp for the resting order behind that size (ProphetX does not continuously re-publish size, so ~27% of rungs are >20 min stale; discount or drop old ones; Kalshi's is the time on its own push update that published exactly that price and size, null until one has — MLB/NBA/NHL/WNBA/NFL/NCAAF/tennis only). `line_movement` webhook/websocket payloads carry `liquidity` + `liquidity_updated_at` inside both `previous` and `current`; a size change with no price move sends nothing. Every player-prop outcome carries `player_id` — a stable, cross-referenceable league player id ("mlb:592450" MLBAM, "nba:"/"wnba:" CDN personId, "nhl:" playerId, "espn:8439" ESPN athlete id for soccer/NFL/NCAAF) — so you can join the SAME player across books without name matching. Null when unconfirmed: a sport with no stats feed (tennis/golf/UFC/... null forever), a never-graded player, a divergent book spelling ("Elmer Rodríguez" gets the id, "Elmer Rodriguez Cruz" stays null), or a shared name (ambiguous). We never guess — a missed join beats a wrong one. Unconditional (no param), player-prop markets only, also on `/results` (same semantics). Coverage warms as games grade after launch. Every team-named leg (h2h, spreads) carries `side` — "home", "away" or "draw" against the event's home_team/away_team (same rule that orders outcomes home-first), null on Over/Under/Yes/No legs and props; use it when an exchange quotes only one leg. Bovada's both_teams_to_score_points ladder carries its threshold in `point` on both Yes/No legs - [GET /v1/sports/{sport_key}/events/{event_id}/odds/history](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/odds/history?apiKey=99c1393f8c921749d193f87b3ef688c5&markets=batter_hits): historical line movement, with optional period filters (from/to, relative_from/relative_to like '-3h'/'0', interval downsample buckets 30s..1h, changes_only=true). Every snapshot carries `liquidity` (stake limit / resting size at that row; Pinnacle's max risk stake), and a Pinnacle limit change with no price move is its own snapshot row — line a limit raise up against the move (Hobby+ all paid tiers full, Free tier returns counts only) - [GET /v1/sports/{sport_key}/events/{event_id}/odds/closing](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/odds/closing?apiKey=99c1393f8c921749d193f87b3ef688c5&markets=h2h,spreads,totals): opening AND closing line per (book, market, outcome) in one call. Closing = last snapshot at or before commence_time (`price`/`point`/`closing_at`); opening = the first snapshot we hold for the outcome, however far before kickoff the book posted it (`opening_price`/`opening_point`/`opening_at`); optional `opening_window=` limits that lookback (14 matches the resolved-props export's opening columns). Both points matter on spreads and totals, where the number moves as much as the price. `opening_age_seconds` says how far before kickoff we first saw it — small values mean we started polling late, so it is not the book's true open. `liquidity` / `opening_liquidity` = the stake limit at each end (Pinnacle's max risk stake; null elsewhere). Canonical CLV helper (Hobby+; free tier redacted) - [GET /v1/sports/{sport_key}/events/{event_id}/movement](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/movement?apiKey=99c1393f8c921749d193f87b3ef688c5&markets=h2h,spreads,totals): line movement derived from the snapshot tick history — per (book, market, outcome) opening line, latest line, implied-probability + point shift; plus a steam[] array flagging outcomes multiple books moved the same direction (sharp-money signal computed across all 116 books). Each steam row carries its line (`open_point` / `latest_point`) and `team` for a team total; exchange openers far off the sportsbook consensus are screened out. Optional `since` (ISO time or `-6h`) measures from that moment; every outcome carries `outcome_id` (+ `book_outcome_id` with `includeBookIds=true`). Hobby+ full; free tier redacted - **Period filter on every odds endpoint (`?period=`)**: filter to game-period markets (1st quarter, 1st half, 1st period, 6th inning, first-N-innings). Canonical codes: `q1` `q2` `q3` `q4` (quarters), `h1` `h2` (halves), `p1` `p2` `p3` (hockey periods), `i1`…`i9` (innings), `f3` `f5` `f7` (first N innings), `map1`…`map7` (esports maps, incl. the `total_kills` / `kills_handicap` / `odd_even_total_kills` / `first_team_to_n_kills` kills markets), `s1`…`s5` (sets — tennis, volleyball), `g1`…`g7` (games — table tennis, badminton). Pass comma-separated for multiple. Omitted = full-game only (backwards-compat). Pass `all` to include every period alongside full game. Coverage across Bovada / DraftKings / FanDuel / Pinnacle on NBA / NHL / MLB / soccer; football period markets shipped August 2026 (DraftKings 1H/1Q game lines, Underdog 1Q/1H player props). - [GET /v1/sports/{sport_key}/events/{event_id}/ev](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/ev?apiKey=99c1393f8c921749d193f87b3ef688c5): cross-book +EV plays with Pinnacle-anchored no-vig fair lines (Hobby+ all paid tiers). Optional markets= and bookmakers= filters; bookmakers= narrows the prices only, never the anchor, so bookmakers=draftkings still returns DK's EV% measured against Pinnacle. The anchor is picked per line and always named — read `fair_source` on each line (and `fair_source_default` for the fallback order pinnacle → polymarket → kalshi → bovada) rather than assuming Pinnacle anchored every line - `GET /v1/sports/{sport_key}/events/{event_id}/ev/calc?market=&name=&point=&description=&price=`: score a price YOU were quoted against the same no-vig fair anchor — for books PropLine doesn't carry (Caesars, Hard Rock, bet365). `name` is the team for h2h/spreads, `Over`/`Under` otherwise; `description` is the player name on prop markets; `price` is American odds. Returns fair_prob, implied_prob, ev_pct, is_plus_ev, fair_source. Full-game markets only. Hobby+ (all paid tiers) - [GET /v1/sports/{sport_key}/events/{event_id}/projections](https://api.prop-line.com/v1/sports/football_nfl/events/25070/projections?apiKey=99c1393f8c921749d193f87b3ef688c5): market-implied consensus projection per (market, player) — the line where the no-vig P(over) crosses 50%, median across contributing sportsbooks. Fields: player, player_id (stable cross-book id, null until first grade), projected_value, consensus_over_prob, books_contributing, last_update. Market-implied arithmetic over sportsbook prices, not a forecast; DFS pick'em pricing excluded. Optional markets= filter. Hobby+ (all paid tiers); free tier gets a redacted teaser - [GET /v1/sports/{sport_key}/events/{event_id}/best-line](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/best-line?apiKey=99c1393f8c921749d193f87b3ef688c5): cross-book line shopping — for every (market, player, line) tuple on the event, the single best American price across all comparable books plus an all_prices array sorted best-first (one row per book, each with last_update). Optional markets= and bookmakers= filters ("shop only my books"); includeLinks=true adds each book's event-page URL (`link`) + mobile app-open deep link (`app_link`, ProphetX only) per price row. DFS pick'em books (PrizePicks/Sleeper/Dabble/ParlayPlay/DraftKings Pick6) excluded; Underdog only at clean payout_multiplier=1.0 lines. Each price row also carries `liquidity` (dollars bettable at that price; ProphetX + Novig resting size, Pinnacle's max risk stake, null elsewhere) — a thin exchange quote often wins the best slot on price alone, so discount rows with small liquidity. Companion to /ev: /ev says whether a price beats the no-vig fair line, /best-line says which book pays the most. Hobby+ (all paid tiers) full; Free tier sees the full structure incl. book identities + best-first ranking with prices nulled (redacted teaser) - [POST /v1/clv/grade](https://api.prop-line.com/v1/clv/grade): closing-line-value grading. POST a list of placed bets (sport_key, event_id, market, bookmaker, selection, side, point, price, optional stake and ref) and each comes back with its closing price, the de-vigged closing fair probability from the sharpest book quoting that line (`fair_source`), `clv_pct` (price-vs-price), `ev_vs_close_pct` (price vs the de-vigged close — the honest number), `beat_close`, and the graded `resolution` + `actual_value` once the game settles, plus a portfolio summary. Stateless: nothing is stored. Matching is fail-closed — a bet that cannot be pinned to exactly one stored outcome returns `matched: false` with an `unmatched_reason` rather than a confident wrong match. Bets on events that have not started yet return `closing_is_final: false` and are excluded from the summary averages. Max 500 bets per request. Hobby+ full; Free sees structure with every number nulled (redacted teaser). CLV is the only durable proxy for whether a bettor has edge, and the graded-result column is one no other odds API can return alongside a closing line - [POST /v1/sports/{sport_key}/events/{event_id}/sgp](https://api.prop-line.com/v1/sports/baseball_mlb/events/150791/sgp): same-game parlay pricing at the book's OWN correlated odds (`bookmaker` = fanduel, draftkings, betonlineag, lowvig, betrivers, betmgm or unibet — the two Chico brands share the Sportcast engine and return the same builder price — or `all` to quote every book on the same legs in one call, with `best_bookmaker` naming the one paying the most). POST 2-10 legs named exactly as /odds names them (market, name, description, point, period, `team` for a team total; for a prop the portable form is primary key + `N+` name + player in description, which pins at every book whether it stores the bet as Over N-0.5, an N+ rung or a per-threshold YES key — or `book_outcome_id` from ?includeBookIds=true, which on betonlineag/lowvig is Sportcast's settlement id) and get back `sgp_price` (the price that book would offer for that slip right now), `independent_price` (the product of the live single-leg prices) and `correlation_factor` (their ratio — the correlation the book is charging for), plus each leg's live single price and `accepted`/`failure_code` where the book refused a leg. `quoted: false` means the book does not offer that combination as an SGP. Matching is fail-closed: a leg that does not pin to exactly one stored outcome is a 422 `leg_unmatched` naming the leg. Quotes for an identical slip are shared for 15s. Hobby+ full; Free sees the matched legs with every price nulled and never triggers a book call. A leg can carry any line the book lists (alt spreads / alt totals, every N+ player rung we store). Send `slips` (up to 25, each with optional `bookmaker`) instead of `legs` to price many slips in one call — `results[]` carries each slip's own `status` + `quote` or `error`. `include_hold: true` also prices the complement slip (one leg flipped) and returns `hold` = (1/sgp + 1/complement) / (1/rest) − 1 - [GET /v1/sports/{sport_key}/events/{event_id}/sgp/legs](https://api.prop-line.com/v1/sports/basketball_nba/events/139523/sgp/legs?apiKey=YOUR_KEY): every outcome each SGP book's pricer can take on this event, with the `book_outcome_id` to send as a leg (alt lines included). Optional `bookmakers=` and `markets=` filters; `supported: false` + `reason` for a book that does not price SGPs on the sport. Cached 10s. Hobby+ prices; Free gets `price` null - [GET /v1/sports/{sport_key}/futures](https://api.prop-line.com/v1/sports/football_nfl/futures?apiKey=99c1393f8c921749d193f87b3ef688c5): season-long futures (outright) markets — championship/Super Bowl/division/conference winners, MVP + award winners, season win totals — aggregated across Bovada, FanDuel, DraftKings, Pinnacle, and Kalshi. One row per (futures event, book, market) with each team/player outcome and its price. Season-long team futures decided by a final regular-season table (win totals, division winners, conference #1 seed on NFL/NBA/MLB) also carry `resolution`, `actual_value` and `settled_at`; postseason futures and awards stay unsettled (null). Optional `?bookmakers=` narrows the per-book rows (the-odds-api-compatible; omitted = all books). Free tier - [GET /v1/sports/{sport_key}/events/{event_id}/results](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/results?apiKey=99c1393f8c921749d193f87b3ef688c5): resolved prop outcomes with actual stat values (Hobby+ all paid tiers full, Free tier redacted with upgrade pointer) - [GET /v1/sports/{sport_key}/scores](https://api.prop-line.com/v1/sports/baseball_mlb/scores?apiKey=99c1393f8c921749d193f87b3ef688c5): game scores and status (free) - [GET /v1/sports/baseball_mlb/grand-salami](https://api.prop-line.com/v1/sports/baseball_mlb/grand-salami?apiKey=99c1393f8c921749d193f87b3ef688c5): synthetic daily MLB Grand Salami — total runs scored + each book's implied Grand Salami line (sum of per-game totals). Free tier; date is the US Eastern slate day, defaults to today. - [GET /v1/sports/hockey_nhl/daily-goals-total](https://api.prop-line.com/v1/sports/hockey_nhl/daily-goals-total?apiKey=99c1393f8c921749d193f87b3ef688c5): synthetic daily NHL goals total — total goals scored (incl. OT/SO) + each book's implied Daily Goals Total line (sum of per-game totals). Hockey's equivalent of the MLB Grand Salami. Free tier; date is the US Eastern slate day, defaults to today. - [GET /v1/sports/{sport_key}/events/{event_id}/stats](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/stats?apiKey=99c1393f8c921749d193f87b3ef688c5): raw box-score stats per player, book-agnostic; live-updating (~90s) during in-progress games for major US sports — MLB + WNBA now, NFL/NCAAF/NBA/NHL at season start; `?stat_type=` filters to named stats, and the stored vocabulary is wider than the market list (NFL `passing_completions`, tennis `sets_won` have no betting market) (free) - [GET /v1/sports/{sport_key}/events/{event_id}/context](https://api.prop-line.com/v1/sports/baseball_mlb/events/12649/context?apiKey=99c1393f8c921749d193f87b3ef688c5): game conditions a prop settles under — MLB: probable starting pitchers + throwing hand (L/R/S, platoon context), confirmed-lineup flag, home-plate umpire, and first-pitch weather; NFL/NCAAF: venue + kickoff weather. Also embedded in /results so every graded prop carries its conditions. Free tier. 404 when no context on file yet - [GET /v1/sports/{sport_key}/players?search=](https://api.prop-line.com/v1/sports/baseball_mlb/players?search=witt&apiKey=99c1393f8c921749d193f87b3ef688c5): player search — stable `player_id` (e.g. `mlb:677951`) plus every spelling the books use (`known_names`), built from graded box scores. `search` 2+ chars, case/accent-insensitive; `limit` 1-100, default 25 (free) - [GET /v1/sports/{sport_key}/players/{player_name}/history](https://api.prop-line.com/v1/sports/baseball_mlb/players/Aaron%20Judge/history?apiKey=99c1393f8c921749d193f87b3ef688c5): per-player prop history with line/price/resolution. `{player_name}` may be a name (expanded to every known spelling — "Bobby Witt" and "Bobby Witt Jr." return the same history) or a `player_id`; response carries `player_id`. Each entry has `is_main_line` (the line that book priced closest to even, among lines standing at kickoff) and `line_moved_in_play`; `?main_line_only=true` keeps only each book's main line per game - [GET /v1/sports/{sport_key}/players/{player_name}/games](https://api.prop-line.com/v1/sports/baseball_mlb/players/Aaron%20Judge/games?apiKey=99c1393f8c921749d193f87b3ef688c5): per-player GAME LOG (name or player_id) — a player's recent games with every raw box-score stat per game, one call instead of one request per event. `?limit=` (1-100; page back with `?before=` + the response's `next_before`), `?season=` + `?season_type=` (preseason|regular|play_in|postseason|cup_final; each game is labeled, with the opponent's code of that season in `opponent_abbr`), `?stat_type=` to narrow, and `?opponent=` for head-to-head (team name, nickname or abbreviation; the limit applies AFTER the filter, so ?opponent=BOS&limit=10 is the last 10 meetings). Reads the raw-stats archive, so it covers every game we hold a box score for — including games no book priced, unlike windows built from /history or /trends. Not capped to the current season. Carries no line, price or grade (free) - [GET /v1/sports/{sport_key}/players/{player_name}/trends](https://api.prop-line.com/v1/sports/baseball_mlb/players/Aaron%20Judge/trends?apiKey=99c1393f8c921749d193f87b3ef688c5): per-player hit-rate trends — over/under/push splits across last 5/10/20/50 graded games per market, current streak, avg actual, recent line. The reference line each game is the reference book's main PREGAME line (never an alt rung, never an in-play line); every market reaches back 50 graded games with or without ?market=; name or `player_id` accepted, response carries `player_id`. Optional ?market= filter and ?dfs_odds_type=standard|goblin|demon (PrizePicks flavor — computes the trend against that flavor's line only). Built on prop resolution; no other odds API offers this. Hobby+ (all paid tiers) full, Free tier returns market list + graded counts with rates redacted - `GET /v1/sports/{sport_key}/events/{event_id}/markets`: which market keys this event actually carries, with an outcomes_count each — cheap discovery before a full odds pull, so you request only the `markets=` you need instead of a 100+ market board. Full-game markets only; counts are STORED offerings, and /odds additionally withholds withdrawn or stale prices, so a count can be higher than what /odds serves — use /odds for what is live - [GET /v1/markets/hit-rates](https://api.prop-line.com/v1/markets/hit-rates?days=28): aggregate Over/Under hit rates per market type, last N days (free) - [GET /v1/markets/resolution-summary](https://api.prop-line.com/v1/markets/resolution-summary?days=30): factual volume of graded props (total/settled/events/sports + per-sport & top-market breakdown), last N days (free) - [GET /v1/dfs/payouts](https://api.prop-line.com/v1/dfs/payouts?apiKey=99c1393f8c921749d193f87b3ef688c5): PrizePicks Power/Flex entry payout schedule (2–6 legs) + the per-leg breakeven win probability for each play. Pass ?leg_win_prob=0.58 to also get expected_return and is_plus_ev per play. Pure reference math (free tier); standard published payouts — demon/goblin per-pick modifiers aren't in PrizePicks's feed so they're not reflected - [GET /v1/sports/{sport}/ids](https://api.prop-line.com/v1/sports/football_nfl/ids): id crosswalk per event — our id, espn_event_id, mlb_game_pk, home/away team ids, merged_from_event_ids, and every sportsbook's own event id + event-page link (books map). Events from 3 days ago to 30 days ahead. Any key incl. free; cached 5 min - [GET /v1/sports/{sport}/injuries](https://api.prop-line.com/v1/sports/football_nfl/injuries): current injury report per sport (NFL, NCAAF, NBA, WNBA, NHL, MLB) — status, status_code, injury, expected_return, status_since, player_id; filters team= and status=. [GET /v1/sports/{sport}/injuries/history](https://api.prop-line.com/v1/sports/football_nfl/injuries/history?days=7) lists every status change (up to 90 days). Source ESPN, refreshed every 10 min. Any key incl. free - [GET /v1/books/accuracy](https://api.prop-line.com/v1/books/accuracy?days=30): which sportsbooks price player props best — each book's closing two-way prop price de-vigged and scored (Brier) against the result and against the other books on the same line; per book skill_bp (+ 95% range), verdict (beats_market / trails_market / in_line), margin_pct; by_sport and by_market breakdowns. Any key incl. free; refreshed hourly - [GET /v1/coverage/history](https://api.prop-line.com/v1/coverage/history?sport=baseball_mlb): per-sport, when each bookmaker's odds history starts in the archive (history_start, game_lines_start, props_start, latest_event, events, retired) — books were added at different times, so start a backtest at the book's date. Any key incl. free; refreshed ~6h - [GET /v1/golf/players/{player}/rounds](https://api.prop-line.com/v1/golf/players/Scottie%20Scheffler/rounds?tour=pga): every completed round for a golfer (strokes, to_par, eagles/birdies/pars/bogeys) newest first, plus last-5/10/20 averages; `tour` = pga, dp_world, liv, lpga, korn_ferry, champions; back to 2024. Any key incl. free - [GET /v1/golf/tournaments](https://api.prop-line.com/v1/golf/tournaments?tour=pga): tournaments we hold golf rounds for, with player and round counts; filter by `tour` and `season`. Any key incl. free - [GET /v1/freshness](https://api.prop-line.com/v1/freshness): per-bookmaker staleness across every book, split into game_lines vs props (`market_classes`) so a prop board going dark behind fresh game lines is visible. Returns market_count, latest_update, staleness_seconds, is_stale per book plus worst_staleness_seconds (age of the oldest non-suspended market on the active board — catches a single silently-stale market the optimistic number hides) and suspended_market_count, with the same per class, plus stale_threshold_seconds and as_of. **No API key required** — poll it to decide whether a book is worth reading, or to alert when one you depend on goes quiet - [GET /v1/exports/resolved-props](https://api.prop-line.com/v1/exports/resolved-props?sport=baseball_mlb): bulk CSV of resolved props with BOTH ends of the line move per row — closing (closing_price/closing_point/closing_at = last snapshot at/before commence_time) and opening (opening_price/opening_point/opening_at = first snapshot in the 14d before kickoff) — a complete CLV/backtest backfill dataset in one download, no per-event history calls. New columns are appended just before customer_token so positional parsers keep working. Rows carry dfs_odds_type (PrizePicks standard/goblin/demon tier; blank for sportsbooks) and payout_multiplier (Underdog per-leg multiplier, 1.0 = standard pick; blank elsewhere). Pro+ (free returns 403). Tier-gated lookback (Pro 90d → Enterprise unbounded) + daily call cap. Archive begins April 2026 (launch) and depth varies by sport — NFL/NCAAF prop grading starts with the 2026 season (September); no graded NFL rows exist yet. Responses carry X-PropLine-Archive-Starts (earliest date held per sport, or "none") and X-PropLine-Archive-Notice when the requested window predates the archive (export will be empty). - [GET /v1/exports/odds-history](https://api.prop-line.com/v1/exports/odds-history?sport=baseball_mlb): bulk CSV of the full line-movement tick history — every recorded snapshot (price + line, per book, incl. period markets), one row per (outcome, snapshot), not just the close; rows carry dfs_odds_type (PrizePicks standard/goblin/demon tier). The raw firehose no subscription tier can bulk-pull; exclusive to the one-time Historical Backfill pass + Enterprise (pass = trailing 2-year lookback, Enterprise unbounded; uncapped calls). Filter by market/bookmaker/since/until (recorded_at); page month-by-month (gigabytes per sport). - [GET /v1/exports/sample](https://api.prop-line.com/v1/exports/sample): public CSV sample of last 7d MLB strikeout props, no auth - `POST /v1/availability/check` · `GET /v1/availability/snapshot` · `GET /v1/availability/health` (beta, Streaming and Enterprise; FanDuel: NFL, NCAAF, MLB, NBA, WNBA, NHL and soccer): live open/suspended state per selection from FanDuel's push feed, ~1-3s behind FanDuel. `check` takes up to 500 `outcome_ids` and returns `state` (open/suspended/unknown/unsupported), a monotonic `version`, `changed_at` and a `current` flag (false = feed degraded or selection off the board; treat as unavailable). `snapshot?event_id=` resyncs after a reconnect; `health` reports per-sport socket state. The push side is the `availability` webhook/socket event: fires on every suspend and reopen, including a reopen at an unchanged price, plus `kind: "feed_status"` messages when a sport's feed turns degraded or recovers. - `POST /v1/webhooks` · `GET /v1/webhooks` · `GET|PATCH|DELETE /v1/webhooks/{id}` · `POST /v1/webhooks/{id}/test` · `GET /v1/webhooks/{id}/deliveries` · `GET /v1/webhooks/{id}/replay` · `WS /v1/stream`: push delivery instead of polling (Streaming Lite $39 = 5 hooks, Streaming $79 = 10). Subscribe a URL to `line_movement`, `resolution`, `steam`, `market_suspended` (a book pulled a market pregame — one delivery per (book, event, player) withdrawal with every key it pulled + `books_agreeing`), `availability` (a FanDuel selection suspended or reopened in play, beta), `line_added` / `line_pulled` (opt-in board deltas for keeping a local board: a line a book posts on an event it already prices or that comes back after a pull, and a line /odds stops serving — same ids and fields as line_movement, `previous` null on added and `current` null on pulled, plus `reason`) and/or `ev` (the push version of /ev — a fresh book price whose EV% vs the no-vig fair line sits inside `min_ev_pct`..`max_ev_pct`); filters (list filters take up to 1,000 chars each, no wildcards; `filter_sport_key` comma-separated sport keys, `filter_event_id`, `filter_market_key` comma-separated market keys, `filter_player_name` substring, `filter_bookmaker_key` comma-separated book keys — same vocabulary as ?bookmakers=, applies to line_movement/resolution/market_suspended, not steam — `min_price_change_pct`, `min_steam_score`, `min_books_agreeing`) are AND-ed and at least one is required below Enterprise. The signing `secret` is returned in full ONCE on create and masked on every later read. Deliveries carry `X-PropLine-Event`, `X-PropLine-Timestamp`, `X-PropLine-Delivery` (dedupe key) and `X-PropLine-Signature` = hex(HMAC-SHA256(secret, f"{timestamp}." + raw_body)) — sign the RAW body, not a re-serialised dict. Retries 10s/30s/2m/10m/30m/1h, six attempts; `/deliveries` returns recent attempts with status + HTTP code for self-service debugging (`limit` up to 200, newest-first; `before_id` pages backwards — pass the smallest id from the previous page). `GET /v1/webhooks/{id}/replay?since_seq=N` re-reads missed events in order from a cursor — every delivery carries `X-PropLine-Sequence`, a per-subscription counter (`X-PropLine-Delivery` is global and cannot be used for gap detection), and the response's `truncated` flag says whether anything after your cursor has already aged out of the 2-day / 5,000-row retention window. **Websocket streaming** (`wss://ws.prop-line.com/v1/stream`, Streaming Lite and up): create the subscription with `transport: "websocket"` and no url, then connect and send `{"type":"auth","api_key":...,"webhook_id":...,"since_seq":N}`. Same events, same filters, same `seq` as a webhook — one subscription, different transport — so a socket and a POST cannot deliver different things. `since_seq` resumes without gaps and the `ready` frame carries the same `truncated` honesty flag. How fast an event reaches the socket depends on the book: DraftKings, FanDuel, Fanatics, Kalshi and Polymarket are ingested from the books' own push feeds, so we receive a line move in about a second (measured in play 2026-09-02, book timestamp to receipt: p50 0.1–1.1s, p90 ≤2s per book), and the write to our database plus `line_movement` adds a few seconds more on top; the other 112 books are polled, so detection there is bounded by the ~30-45s in-play cycle above. Concurrent connections capped per plan (Streaming Lite 2, Streaming 5); delivered events are not metered. `format: "discord"` rewrites payloads as Discord embeds (unsigned — Discord doesn't verify) ## Event identity and orientation One fixture is one `id` across every bookmaker. `home_team`/`away_team` are DISPLAY names, not identifiers — they are corrected over time and change when two rows are merged, so never key on them (a merged id keeps resolving, but then returns the surviving row's spelling and start time). Orientation is normalized ONCE at the event level and applies to every bookmaker in the response: exchanges (Kalshi, Polymarket) publish no home/away signal and some sportsbook feeds list the home side first, so PropLine resolves one orientation per fixture and confirms it against the league's scores feed after the game. Outcome order within a market is deterministic and derived from the data, not from storage — team markets (`h2h`, `spreads`, `draw_no_bet`, ...) are ordered home, then away, then Draw (the-odds-api's convention); player and total markets are grouped by subject with Over/Yes before Under/No. Each bookmaker block carries that book's OWN spelling in its outcome names — to join onto a book's native feed use `includeBookIds=true` and match on ids, not names. When two rows turn out to be the same fixture we merge them; `merged_from_event_ids` on `/events` and both `/odds` endpoints lists the ids that were merged INTO this event (strings, null for events that never merged, always present — no flag), so a stored id can be reconciled from the response you were already fetching instead of re-requesting each saved id. On MLB/NBA/WNBA/NHL/NFL the names are the franchise's full name ("Boston Bruins", never "BOS Bruins" or "Bruins") on every endpoint, webhook and export; other sports carry the spelling of the book that first listed the event. `is_outright` (on `/events` and both `/odds` endpoints) is true for a tournament/outright listing (tennis, golf, racing, cycling winner markets, e.g. "WTA Seoul") — `away_team` is "" on those rows; filter on it to keep only matchups. For TEAM identity, `home_team_key`/`away_team_key` (on `/events`, both `/odds` endpoints and `/scores`) are stable permanent join keys — every book spelling of a club resolves to the same key ("St Mirren FC"/"St. Mirren" -> `st_mirren`), keys are never renamed once published, and the field is null where the team cannot be identified with certainty (individual sports; fall back to the name). `home_team_id`/`away_team_id` additionally carry the LEAGUE's own permanent team id, namespaced (`mlb:147`, `espn.soccer:363`, `espn.nfl:12`) — use the key inside PropLine, the id to join against external datasets; sourced from the grading stats feeds, never guessed, null where unconfirmed. `home_team_logo_url`/`away_team_logo_url` give a public PNG logo image built from that id (league or ESPN CDN; null when the id is null). `espn_event_id` (on `/events` and `/scores`) is ESPN's own id for the FIXTURE, kept from the match PropLine's live-scores loop already makes — join on it to read score and clock straight from ESPN while taking odds from PropLine; set for soccer and football, null for MLB/NBA/NHL/WNBA (their scores come from each league's own API) and for tennis. `mlb_game_pk` (on `/events` and `/scores`, MLB only) is the MLB Stats API gamePk — set on a unique match of teams + start time (exact, or the only game of the pair within 8h), and the event's commence_time is pinned to MLB's; null when ambiguous or postponed; use it to tell doubleheader games apart. `tournament` / `tour` (tennis only, on `/events`, both `/odds` endpoints and `/scores`) say which competition a match is: `tournament` is the first book's competition name ("ATP Chengdu", "ITF M25 Pardubice"), `tour` one of `ATP`/`WTA`/`Challenger`/`ITF`/`UTR`/`Exhibition`/`Team` (WTA 125 = `WTA`); set once, never change, null when no book named it — filter the single `tennis` key by tour with these. ## SDKs - [Python](https://pypi.org/project/propline/): `pip install propline` - [Node / TypeScript](https://www.npmjs.com/package/propline): `npm install propline` - [MCP server](https://www.npmjs.com/package/propline-mcp): hosted at `https://mcp.prop-line.com/mcp` (Streamable HTTP, `Authorization: Bearer `), or local `npx -y propline-mcp` — gives Claude / ChatGPT / Cursor / any MCP client direct access to live odds - [CLI](https://www.npmjs.com/package/propline-cli): `npm install -g propline-cli` (or `npx propline-cli`) — pretty-printed terminal output for `sports`, `events`, `odds`, `scores`, `live`, `ev`, `player-history`, `export-resolved-props`, `export-odds-history`, and `webhooks`. `--json` flag opts out for `jq` piping. Auth via `PROPLINE_API_KEY` env var or `--api-key`. ## For AI agents PropLine is built to be driven by an AI agent end-to-end, not just by human developers: - **You already know the response format.** Responses are the-odds-api compatible (`bookmakers[] → markets[] → outcomes[]`), the shape most LLMs have seen extensively in training. Code written for the-odds-api works after changing the base URL. - **MCP server**: hosted Streamable HTTP endpoint `https://mcp.prop-line.com/mcp` (send `Authorization: Bearer `; no key = shared demo key), or local `npx -y propline-mcp` with env `PROPLINE_API_KEY` — gives any MCP client (Claude Desktop, Claude Code, ChatGPT) 29 tools covering the full REST surface — odds, props, resolution, +EV, best-line, trends, futures, movement/steam, exports. On the demo key, `propline_create_free_api_key` signs the user up from the chat (asks for their email; the key is emailed, never returned). Listed in the MCP Registry and Glama. - **Machine-actionable errors.** Gated and throttled responses return a structured `detail` object: `{"error": "", "message": "", ...}`. Codes: `missing_api_key` / `invalid_api_key` (401), `upgrade_required` (403 — includes `required_tier` and `upgrade_url`), `burst_limit_exceeded` (429 — includes `retry_after_seconds` + `Retry-After` header), `daily_limit_exceeded` (429 — includes a pre-filled one-click `upgrade_url`, plus a `Retry-After` header; reset is unix seconds at the top of the next UTC day). An agent hitting a gate can report the exact unlock path to its user instead of failing. - **Live quota headers on every response.** Every authenticated response carries `X-Daily-Limit` / `X-Daily-Used` / `X-Daily-Remaining` / `X-Daily-Reset` (plus `RateLimit-Remaining` / `X-RateLimit-Remaining`) — including on 4xx errors, though not on a 401 for an invalid key — so usage can be tracked programmatically without a dashboard — an agent can see the cap coming and back off (or recommend an upgrade) before hitting the 429. - **Redacted teasers, not dead ends.** Free-tier calls to paid analytical endpoints (/ev, /best-line, /odds/history, /trends…) return the full response *structure* with prices/analytics nulled and `redacted: true` + `upgrade_url` — so an agent can show its user exactly what upgrading unlocks. - **Agent landing page**: https://prop-line.com/for-ai-agents ## Reference repos (open-source examples) - [propline-arb-finder](https://github.com/proplineapi/propline-arb-finder): scan upcoming events for cross-book arbitrage, prints stake split - [propline-clv-tracker](https://github.com/proplineapi/propline-clv-tracker): take CSV of placed bets → report CLV%, stake-weighted CLV, EV$ - [propline-parlay-ev](https://github.com/proplineapi/propline-parlay-ev): parlay JSON → joint no-vig probability → parlay EV% ## Optional - [Webhook subscriptions](https://prop-line.com/docs#webhooks): HMAC-signed push deliveries for `line_movement`, `resolution`, `steam` (cross-book sharp-money alert — the push version of the /movement steam signal, carrying the same `team` / `open_point` / `latest_point` line identity; filter by `min_steam_score`) `market_suspended` (a book took a market off the board pregame; filter by `min_books_agreeing`), `line_added` / `line_pulled` (a line appeared on or left a book's board) and `ev` (a fresh price above the no-vig fair line; filter by `min_ev_pct` / `max_ev_pct`) events (Streaming Lite tier and up) - [Discord webhook integration](https://prop-line.com/discord-webhooks): point a webhook subscription at a Discord channel; PropLine rewrites payloads as Discord embeds - [Migration from the-odds-api](https://prop-line.com/switch-from-the-odds-api): drop-in compatibility — change one base URL, get player props + resolution + +EV - [PropLine vs the-odds-api buyer's guide](https://prop-line.com/the-odds-api-vs-propline): 17-row feature scorecard, three pricing scenarios, decision tree