API Documentation
Everything you need to integrate PropLine into your app.
Building with an AI assistant? Pre-load the full PropLine reference into your model of choice:
Quick Start
Get up and running in 30 seconds:
- Get your API key from the signup form
- Make your first request:
curl "https://api.prop-line.com/v1/sports?apiKey=YOUR_API_KEY"Or skip the curl boilerplate — PropLine ships official SDKs and tools for every common workflow:
Authentication
Pass your API key via query parameter or header:
# Query parameter
curl "https://api.prop-line.com/v1/sports?apiKey=YOUR_API_KEY"
# Header
curl -H "X-API-Key: YOUR_API_KEY" "https://api.prop-line.com/v1/sports"Bookmakers
Every odds response returns a bookmakers array so you can compare lines across books in a single request. Iterate the array to line-shop between sources.
| Key | Book | Coverage |
|---|---|---|
| bovada | Bovada | All 38 sports — game lines + full player props |
| draftkings | DraftKings | MLB, NBA, NHL, NFL, NCAAF + 9 soccer leagues — game lines + player props (NFL/NCAAF game lines now; player props at preseason) |
| fanduel | FanDuel | MLB, NBA, NHL, NFL, NCAAF + 9 soccer leagues — game lines + player props (NFL/NCAAF game lines now; player props at preseason) |
| betmgm | BetMGM | MLB, NBA, 17 soccer leagues — game lines + MLB player props (pitcher/batter) |
| betrivers | BetRivers | MLB, NBA, NHL, 6 soccer leagues — full prop suite incl. NHL Player Points tiers, NBA double/triple-double YES, soccer To Score or Assist |
| pinnacle | Pinnacle | MLB (game lines + props), NBA/NHL/NFL + 27 soccer leagues (game lines, goalie saves) — sharpest US-facing book |
| unibet | Unibet | MLB/NBA/NHL + 6 soccer leagues — game lines; NBA + NHL + soccer player props (points, rebounds, assists, threes, steals, blocks, PRA, shots on goal, goalscorer, cards, BTTS, total corners) |
| onexbet | 1xBet | MLB, NBA, WNBA, NHL + 13 soccer leagues — game lines (h2h, spreads, totals) |
| tab_au | TAB (Australia) | MLB, NBA, WNBA, NHL + 13 soccer leagues — game lines (h2h, spreads, totals). Australia's largest licensed wagering operator. |
| prizepicks | PrizePicks (DFS) | MLB, NBA, NHL, 27 soccer leagues, tennis, UFC — player projections at synthetic +100/+100 even-money pricing (DFS payouts scale with parlay correct-count) |
| underdog | Underdog Fantasy (DFS) | MLB, NBA, NHL, tennis, UFC + 9 soccer leagues — player props with real two-way American prices (e.g. -113/+101) and an optional payout multiplier on boosted picks |
| kalshi | Kalshi (event-contract exchange) | MLB, NBA, NHL, NFL, NCAAF + EPL/La Liga/Serie A/Bundesliga/Ligue 1/MLS/Scottish Premiership — game-line h2h moneylines (NFL/NCAAF series load year-round; CFTC-regulated US exchange; binary YES/NO contracts converted to American odds) |
| polymarket | Polymarket (prediction-market exchange) | MLB, NBA, NHL + 13 soccer leagues — game-line h2h, multi-line totals, and spreads (US sports bundle all three; soccer is 3-way h2h re-assembled from binary YES/NO markets) |
| matchbook | Matchbook (back/lay exchange) | MLB, NBA, NHL + 17 soccer leagues + tennis + boxing — game lines (h2h, totals, spreads). Best back price per runner. |
| smarkets | Smarkets (back/lay exchange) | MLB, NBA, NHL + 13 soccer leagues — Match Winner + alt-total + alt-handicap lines. UK exchange with best back price per contract. |
| novig | Novig (P2P exchange) | MLB, NBA, WNBA, NHL + 13 soccer leagues — deepest per-event surface (MLB ~40 markets/event w/ full batter & pitcher prop suite, NBA ~140 markets/event incl. DOUBLE_DOUBLE / TRIPLE_DOUBLE, NHL player goals + saves). US peer-to-peer exchange; `last` field is implied probability converted to American odds. |
More books are actively being added. You don't need to specify a bookmaker in requests — every response includes every book that carries lines for the requested market.
Timestamps & Data Guarantees
For CLV tracking, line-movement analysis, and any time-sensitive modeling, the meaning of every timestamp matters as much as the timestamp itself. This section lays out exactly what each field represents, what we guarantee, and where the underlying book APIs limit what's possible.
Two timestamps per snapshot
Every snapshot in /odds/history and every current outcome in /odds can carry up to two timestamps:
recorded_at(system-seen) — when our scraper observed and persisted this odds. Always populated. Sub-second wall-clock precision relative to our database.book_updated_at(book-published)— when the book itself reports this odds was last set. Populated only for books that expose a publish-time signal in their API. Today that's Bovada (per-eventlastModified); BetRivers, DraftKings, FanDuel, PrizePicks, Underdog, Kalshi, and Polymarket all returnnull.book_version(market version counter) — a monotonic integer the book bumps on every market update. Today only Pinnacle exposes one (`market.version`); other books returnnull. Captured at the moment of the snapshot/price change — comparing versions across two snapshots tells you how many distinct market updates the book recorded between them, even if only some changed the visible price.
The gap between the two — when populated on both sides — is your scraper-side latency for that book. We don't fabricatebook_updated_atfor books that don't expose it, because a fake value would be indistinguishable from a real one to your model.
Sequence preservation
Snapshots are stored with a monotonic recorded_at per outcome and read back in time order via the (outcome_id, recorded_at) index. Within an outcome, you will not see line movements out of order. Across outcomes within the same event, ordering is consistent because all markets ingested in a single poll cycle share that cycle's transaction commit time as their lower bound.
Snapshots are full states, not deltas
Every snapshot is a complete record of the price/point at that moment — never a delta against a prior snapshot. You can replay any subset of an outcome's history without needing other snapshots for context. Snapshots are written only on change: if a poll cycle returns the same price + point as the prior one, no new row is created. This keeps storage tight without losing information.
Polling cadence & missed ticks
We poll each book on a fixed interval. Any line move within a single interval is collapsed into one snapshot at our next observation — we cannot recover intra-poll micro-moves the book may have flashed and reverted.
- Pre-game multi-book sweep: 60 seconds
- Live in-progress game-line movement: 30 seconds
- Long-cycle low-volume sports: 60s sweep, less frequent per book
For most CLV and steam-detection workflows this is sufficient — the books themselves don't change pre-game lines faster than every 30–60 seconds in calm windows, and our 30s live cadence covers most in-play movement. See /freshness for live per-book staleness. If your workflow requires sub-second freshness on a specific book, talk to us about a direct push integration via webhooks.
Normalization vs raw
Prices pass through unchanged from the book — American odds are what the book quoted, decimal odds are computed deterministically from the American value. The fields we normalize across books arestructural, not numeric: team names, market keys, player names. The raw forms aren't exposed because the structural normalization is what makes cross-book comparison meaningful in the first place; if you need a specific book's raw shape, hit that book's feed directly.
Endpoints
Base URL: https://api.prop-line.com/v1
| Method | Endpoint | Description |
|---|---|---|
| GET | /sports | List available sports |
| GET | /sports/{sport}/events | List upcoming events |
| GET | /sports/{sport}/odds | Bulk odds (game lines) |
| GET | /sports/{sport}/events/{id}/odds | Event odds + player props |
| GET | /sports/{sport}/events/{id}/odds/history | Historical line movement — period filters, downsample, change-only (Hobby+) |
| GET | /sports/{sport}/events/{id}/odds/closing | Closing line per (book, market, outcome) — CLV helper (Hobby+) |
| GET | /sports/{sport}/scores | Game scores & status |
| GET | /sports/baseball_mlb/grand-salami | Synthetic daily Grand Salami (total runs + per-book line) |
| GET | /sports/hockey_nhl/daily-goals-total | Synthetic daily NHL goals total (total goals + per-book line) |
| GET | /sports/{sport}/events/{id}/results | Resolved prop outcomes (Pro) |
| GET | /sports/{sport}/players/{name}/history | Player prop history with resolution (Pro) |
| GET | /sports/{sport}/players/{name}/trends | Player hit-rate trends (L5/L10/L20/L50) (Pro) |
| GET | /sports/{sport}/events/{id}/ev | Cross-book +EV with no-vig fair lines (Pro) |
| GET | /sports/{sport}/futures | Futures markets — championship winner, MVP, etc. |
| GET | /sports/{sport}/events/{id}/stats | Raw player/team stats from box scores |
| GET | /exports/resolved-props | Bulk CSV export of resolved props + closing lines (Pro) |
| GET | /exports/odds-history | Bulk CSV of the full line-movement tick history (Backfill / Enterprise) |
| GET | /exports/sample | Free public CSV sample — last 7 days MLB K props |
List Sports
GET /v1/sportsReturns all available sports with their current status.
Response:
[
{
"key": "baseball_mlb",
"title": "MLB",
"active": true
}
]List Events
GET /v1/sports/{sport_key}/eventsReturns upcoming events for a sport. No odds included (use the odds endpoint for that).
Response:
[
{
"id": "10",
"sport_key": "baseball_mlb",
"home_team": "Colorado Rockies",
"away_team": "Philadelphia Phillies",
"commence_time": "2026-04-05T19:10:00Z"
}
]Get Odds (Bulk)
GET /v1/sports/{sport_key}/odds?markets=h2h,spreads,totalsReturns odds for all upcoming events. Use the markets parameter to filter by market type (comma-separated).
Player Props (Per Event)
GET /v1/sports/{sport_key}/events/{event_id}/odds
?markets=pitcher_strikeouts,batter_hits,batter_home_runsThis is the primary endpoint for player props. Pass one or more prop market keys via the markets parameter.
Response:
{
"id": "10",
"sport_key": "baseball_mlb",
"home_team": "Colorado Rockies",
"away_team": "Philadelphia Phillies",
"commence_time": "2026-04-05T19:10:00Z",
"bookmakers": [
{
"key": "bovada",
"title": "Bovada",
"markets": [{
"key": "pitcher_strikeouts",
"last_update": "2026-04-05T18:46:30Z",
"outcomes": [
{ "name": "Over", "description": "Zack Wheeler",
"price": -130, "point": 6.5 },
{ "name": "Under", "description": "Zack Wheeler",
"price": 100, "point": 6.5 }
]
}]
},
{
"key": "draftkings",
"title": "DraftKings",
"markets": [{
"key": "pitcher_strikeouts",
"last_update": "2026-04-05T18:46:42Z",
"outcomes": [
{ "name": "Over", "description": "Zack Wheeler",
"price": -125, "point": 6.5 },
{ "name": "Under", "description": "Zack Wheeler",
"price": 105, "point": 6.5 }
]
}]
},
{
"key": "fanduel",
"title": "FanDuel",
"markets": [{
"key": "pitcher_strikeouts",
"last_update": "2026-04-05T18:46:38Z",
"outcomes": [
{ "name": "Over", "description": "Zack Wheeler",
"price": -135, "point": 6.5 },
{ "name": "Under", "description": "Zack Wheeler",
"price": 110, "point": 6.5 }
]
}]
},
{
"key": "pinnacle",
"title": "Pinnacle",
"markets": [{
"key": "pitcher_strikeouts",
"last_update": "2026-04-05T18:46:45Z",
"outcomes": [
{ "name": "Over", "description": "Zack Wheeler",
"price": -128, "point": 6.5 },
{ "name": "Under", "description": "Zack Wheeler",
"price": 108, "point": 6.5 }
]
}]
},
{
"key": "prizepicks",
"title": "PrizePicks",
"markets": [{
"key": "pitcher_strikeouts",
"last_update": "2026-04-05T18:46:50Z",
"outcomes": [
// DFS projection — synthetic +100 pricing on both sides.
// Payout scales with parlay correct-count, not per-pick odds.
{ "name": "Over", "description": "Zack Wheeler",
"price": 100, "point": 6.5 },
{ "name": "Under", "description": "Zack Wheeler",
"price": 100, "point": 6.5 }
]
}]
}
]
}Historical Line Movement (Hobby+)
GET /v1/sports/{sport_key}/events/{event_id}/odds/history
?markets=pitcher_strikeouts # default h2h,spreads,totals
&relative_from=-3h # 3h before commence_time
&relative_to=0 # commence_time itself
&interval=1m # one snapshot per minute per outcome
&changes_only=true # drop unchanged bucketsFull snapshot history per outcome. Paid tiers get the raw stream; free tier sees market structure with redacted: true and a count of available snapshots.
Period-historical query params
All optional. Combine to scope, downsample, and de-noise — the same data you'd post-process today, computed server-side in one call.
from,to— absolute ISO timestamps. Bound the snapshot window directly.relative_from,relative_to— offsets relative tocommence_time. Forms:-3h,-30m,-90s,0. Mutually exclusive with the absolute counterpart.interval— downsample to one snapshot per bucket. One of30s,1m,5m,15m,30m,1h. We pick the last snapshot in each bucket.changes_only— whentrue, drop rows whose(price, point)matches the previous row. The opening line is always kept.
Tier-gated depth by event age: Hobby = 30 days, Pro = 90 days, Streaming Lite = 180 days, Streaming = 365 days, Enterprise = unlimited. Older events return the redacted shape with an upgrade_url.
Closing Lines / CLV (Hobby+)
GET /v1/sports/{sport_key}/events/{event_id}/odds/closing
?markets=h2h,spreads,totals,pitcher_strikeoutsThe last snapshot per outcome at or before commence_time— the canonical “closing line” that CLV-tracking tools measure against. One call replaces the “fetch full history → find the latest pre-game row” pattern.
Response:
{
"id": "5885",
"sport_key": "baseball_mlb",
"home_team": "Seattle Mariners",
"away_team": "Texas Rangers",
"commence_time": "2026-04-19T20:10:00Z",
"bookmakers": [
{
"key": "draftkings",
"title": "DraftKings",
"markets": [
{
"key": "pitcher_strikeouts",
"description": "Pitcher Strikeouts",
"outcomes": [
{
"name": "Over",
"description": "Bryan Woo",
"price": 116,
"point": 6.5,
"closing_at": "2026-04-19T20:08:14Z",
"book_updated_at": null,
"book_version": null
},
{
"name": "Under",
"description": "Bryan Woo",
"price": -148,
"point": 6.5,
"closing_at": "2026-04-19T20:08:14Z"
}
]
}
]
}
]
}closing_at is the recorded_at of the snapshot we picked — useful for confirming the data point came from right before tip rather than hours earlier. Same per-tier event-age cap as /odds/history.
Period Markets
Markets bucketed by game period — 1st quarter spread, 2nd half total, 1st period puck line, 6th inning run line. Every odds endpoint accepts an optional period query param. Omitted = full game (default; backwards-compatible). Pass canonical codes or all to opt in.
# Last 30 min of 1st-half spread movement before tip
GET /v1/sports/basketball_nba/events/{event_id}/odds/history
?markets=spreads&period=h1&relative_from=-30m
# Closing line for the 1st-quarter total
GET /v1/sports/basketball_nba/events/{event_id}/odds/closing
?markets=totals&period=q1
# Every period (quarters + halves + full game) in one response
GET /v1/sports/basketball_nba/events/{event_id}/odds?period=allCanonical period codes
| Code | Meaning | Applies to |
|---|---|---|
| q1, q2, q3, q4 | Quarters | NBA, WNBA, NCAAB, NFL, NCAAF |
| h1, h2 | Halves | Basketball, football, soccer |
| p1, p2, p3 | Periods | NHL |
| i1 … i9 | Innings | MLB |
| f3, f5, f7 | First N innings | MLB |
Every market row in the response carries a period field (string or null for full game), so consumers can branch on it without re-parsing the URL.
Coverage today: Bovada, DraftKings, FanDuel, and Pinnacle all carry period markets across NBA / NHL / MLB / soccer. Football (NFL / NCAAF) period markets land alongside the September player-prop rollout.
Game Scores
GET /v1/sports/{sport_key}/scores?days_from=3Returns game scores and status for recent events. Free tier. Use days_from to control how many days back to include (default: 3).
Response:
[
{
"id": "16",
"sport_key": "baseball_mlb",
"home_team": "Detroit Tigers",
"away_team": "St. Louis Cardinals",
"commence_time": "2026-04-05T23:20:00Z",
"status": "final",
"home_score": 3,
"away_score": 5
}
]MLB Grand Salami
GET /v1/sports/baseball_mlb/grand-salami?date=2026-05-22Synthetic daily Grand Salami for MLB — total runs scored across every game on a given UTC date, plus each book's implied Grand Salami line (sum of their primary game totals). No retail book quotes this as a single market, so cross-book historical data isn't available elsewhere. Free tier. Default date is today (UTC).
Response:
{
"sport_key": "baseball_mlb",
"date": "2026-05-22",
"games_total": 15,
"games_completed": 15,
"games_in_progress": 0,
"games_upcoming": 0,
"actual_total_runs": 142,
"bookmakers": [
{ "key": "bovada", "title": "Bovada", "games_priced": 15, "line": 134.5, "result": "over" },
{ "key": "draftkings", "title": "DraftKings", "games_priced": 15, "line": 135.0, "result": "over" },
{ "key": "pinnacle", "title": "Pinnacle", "games_priced": 15, "line": 133.5, "result": "over" }
]
}NHL Daily Goals Total
GET /v1/sports/hockey_nhl/daily-goals-total?date=2026-05-24Synthetic daily goals total for NHL — total goals scored (incl. OT/SO) across every NHL game on a given UTC date, plus each book's implied Daily Goals Total line (sum of their primary game totals). Hockey's equivalent of the MLB Grand Salami; no retail book quotes it as a single market. Free tier. Default date is today (UTC).
Response:
{
"sport_key": "hockey_nhl",
"date": "2026-05-24",
"games_total": 4,
"games_completed": 4,
"games_in_progress": 0,
"games_upcoming": 0,
"actual_total_goals": 23,
"bookmakers": [
{ "key": "bovada", "title": "Bovada", "games_priced": 4, "line": 24.5, "result": "under" },
{ "key": "draftkings", "title": "DraftKings", "games_priced": 4, "line": 24.0, "result": "under" },
{ "key": "pinnacle", "title": "Pinnacle", "games_priced": 4, "line": 24.5, "result": "under" }
]
}Prop Results (Pro)
GET /v1/sports/{sport_key}/events/{event_id}/results
?markets=pitcher_strikeouts,batter_hitsReturns resolved prop outcomes with actual player stats. Pro tier only. Each outcome includes whether it won, lost, or pushed, plus the actual stat value.
Response:
{
"id": "16",
"sport_key": "baseball_mlb",
"home_team": "Detroit Tigers",
"away_team": "St. Louis Cardinals",
"status": "final",
"home_score": 3,
"away_score": 5,
"bookmakers": [{
"key": "bovada",
"title": "Bovada",
"markets": [{
"key": "pitcher_strikeouts",
"description": "Total Strikeouts - Tarik Skubal (DET)",
"outcomes": [
{
"name": "Over",
"description": "Tarik Skubal (DET)",
"price": -150,
"point": 6.5,
"resolution": "won",
"actual_value": 7.0,
"resolved_at": "2026-04-06T03:15:00Z"
},
{
"name": "Under",
"description": "Tarik Skubal (DET)",
"price": 120,
"point": 6.5,
"resolution": "lost",
"actual_value": 7.0,
"resolved_at": "2026-04-06T03:15:00Z"
}
]
}]
}]
}Resolution values: won, lost, push, void (player scratched)
Cross-book +EV (Pro)
GET /v1/sports/{sport_key}/events/{event_id}/ev
?markets=pitcher_strikeouts,batter_hits # optionalFor each (market, player, line) on an event, derives a no-vig fair line from a sharp anchor (Pinnacle preferred, Bovada fallback) and returns the expected value (EV%) for every other book's price at the same line. Outcomes are sorted with +EV plays floated to the top. Pro tier only.PrizePicks is excluded — its synthetic +100/+100 prices aren't payout odds.
Response:
{
"id": "12345",
"sport_key": "baseball_mlb",
"home_team": "Yankees",
"away_team": "Red Sox",
"commence_time": "2026-04-25T23:05:00Z",
"fair_source_default": "pinnacle → polymarket → kalshi → bovada (first available per market)",
"lines": [
{
"market_key": "pitcher_strikeouts",
"description": "Gerrit Cole",
"point": 6.5,
"fair_source": "pinnacle",
"fair_probs": { "Over": 0.52, "Under": 0.48 },
"outcomes": [
{ "book": "fanduel", "book_title": "FanDuel",
"name": "Over", "price": 110, "ev_pct": 9.20,
"is_plus_ev": true },
{ "book": "draftkings", "book_title": "DraftKings",
"name": "Over", "price": -105, "ev_pct": 1.30,
"is_plus_ev": true },
{ "book": "pinnacle", "book_title": "Pinnacle",
"name": "Over", "price": -110, "ev_pct": -3.80,
"is_plus_ev": false }
]
}
]
}Lines without sharp-anchor coverage on this event (or single-tier YES markets like “10+ Strikeouts” that can't be no-vig fair-derived from one price) are dropped from the response.
Player Prop History (Pro)
GET /v1/sports/{sport_key}/players/{player_name}/history
?market=pitcher_strikeouts
&bookmaker=draftkings # optional
&limit=20 # default 20, max 100Returns a player's recent resolved props for a given market — line, Over/Under prices, and whether each side won or lost. Pro tier only for resolution data. Free tier sees event structure with redacted: true.
Response:
{
"player_name": "Bryan Woo",
"sport_key": "baseball_mlb",
"market": "pitcher_strikeouts",
"entries": [
{
"event_id": "5885",
"commence_time": "2026-04-19T20:10:00Z",
"home_team": "Seattle Mariners",
"away_team": "Texas Rangers",
"bookmaker": "draftkings",
"bookmaker_title": "DraftKings",
"line": 6.5,
"over_price": 116,
"under_price": -148,
"actual_value": 6.0,
"over_result": "lost",
"under_result": "won",
"resolved_at": "2026-04-19T23:18:45Z",
"redacted": false
}
]
}One entry per (event, bookmaker) pair. Name match is case-insensitive prefix, so both Bryan Woo and bryan woo work.
Player Hit-Rate Trends (Pro)
GET /v1/sports/{sport_key}/players/{player_name}/trends
?market=batter_home_runs # optional — omit for every marketThe “did X go over in N of his last M games?” surface. For every market the player has graded history in, returns over/under/push splits across the last 5 / 10 / 20 / 50graded games, the current streak, average actual stat, and the most recent line. The verdict each game compares the player's realstat (book-agnostic) against one reference book's posted line; pushes are excluded from over_pct. Built entirely on PropLine's prop resolution — no other odds API offers this. Pro tier for the rates; free tier sees the market list + graded-game counts with rates redacted.
Response:
{
"player_name": "Aaron Judge",
"sport_key": "baseball_mlb",
"markets": [
{
"market": "batter_total_bases",
"games_graded": 50,
"reference_bookmaker": "bovada",
"reference_bookmaker_title": "Bovada",
"recent_line": 1.5,
"avg_actual": 2.02,
"last_5": { "window": 5, "games": 5, "over": 2, "under": 3, "push": 0, "over_pct": 40.0 },
"last_10": { "window": 10, "games": 10, "over": 3, "under": 7, "push": 0, "over_pct": 30.0 },
"last_20": { "window": 20, "games": 20, "over": 9, "under": 11,"push": 0, "over_pct": 45.0 },
"last_50": { "window": 50, "games": 50, "over": 24,"under": 26,"push": 0, "over_pct": 48.0 },
"current_streak": { "result": "under", "length": 2 },
"last_game": {
"event_id": "12649",
"commence_time": "2026-05-29T23:05:00Z",
"line": 1.5,
"actual_value": 1.0,
"result": "under"
},
"redacted": false
}
]
}Markets are sorted most-active first. A window is only returned once enough games exist to make it meaningful (e.g. last_20needs 11+ graded games), otherwise it's null.
Resolution Coverage (Free)
GET /v1/markets/resolution-summary
?days=30 # 1-90, default 30Aggregated counts only — the factual volume of player props we've graded against real box scores over the window. Free tier. A coverage proof, not a profitability claim: the-odds-api and OddsJam grade zero of these at any tier.
Response:
{
"days": 30,
"total_graded": 712043,
"total_settled": 698811,
"events_graded": 4120,
"sports_covered": 33,
"by_sport": [
{ "sport_key": "baseball_mlb", "title": "MLB",
"graded": 386415, "events": 383 }
],
"top_markets": [
{ "market_key": "batter_total_bases", "graded": 48210 }
]
}total_graded includes voids; total_settled is won/lost/push only. top_markets is capped at 12.
Futures Markets
GET /v1/sports/{sport_key}/futuresSeason-long markets — World Series winner, NBA championship, Stanley Cup, league MVP, division winners, etc. One entry per (futures event, book, market), with every team or player priced. Free tier. Polled hourly.
Response:
[
{
"id": "12345",
"sport_key": "baseball_mlb",
"title": "World Series 2026",
"commence_time": "2026-10-31T00:00:00Z",
"markets": [
{
"key": "world_series_winner",
"description": "World Series Winner",
"bookmaker": "bovada",
"bookmaker_title": "Bovada",
"last_update": "2026-04-27T15:30:51Z",
"book_updated_at": "2026-04-27T15:14:11Z",
"outcomes": [
{ "name": "Los Angeles Dodgers", "price": 180, "price_decimal": 2.8 },
{ "name": "New York Yankees", "price": 725, "price_decimal": 8.25 },
{ "name": "Seattle Mariners", "price": 1200, "price_decimal": 13.0 }
]
}
]
}
]Available sports: MLB, NBA, NHL, NFL, NCAAB, NCAAF. Market keys are slugified from the book's description with year suffixes dropped, so they're stable across seasons — world_series_winner, stanley_cup_winner, nba_mvp. Filter client-side on market.key to find the one you want.
Player Stats
GET /v1/sports/{sport_key}/events/{event_id}/statsReturns raw player and team stats from official box scores. This data is book-agnostic — use it to resolve props from any sportsbook, build your own models, or power research dashboards. Free tier.
Response:
{
"id": "16",
"sport_key": "baseball_mlb",
"home_team": "Detroit Tigers",
"away_team": "St. Louis Cardinals",
"status": "final",
"home_score": 3,
"away_score": 5,
"players": [
{
"name": "Tarik Skubal",
"team": "Detroit Tigers",
"stats": {
"strikeouts": 7,
"earned_runs": 2,
"hits_allowed": 5,
"innings_pitched": 6.0
}
},
{
"name": "Masyn Winn",
"team": "St. Louis Cardinals",
"stats": {
"hits": 2,
"home_runs": 1,
"rbis": 3,
"total_bases": 5
}
}
]
}Stats are sourced from official league APIs (MLB, NBA, NHL, NCAAB, ESPN) and are available once a game reaches final status. Use this endpoint alongside odds from any sportsbook to build your own prop resolution engine.
Bulk Data Export (Pro)
GET /v1/exports/resolved-props
?sport=baseball_mlb
&market=pitcher_strikeouts # optional
&bookmaker=draftkings # optional
&since=2026-04-01T00:00:00Z # optional, ISO datetime
&until=2026-04-30T23:59:59Z # optional, ISO datetimeStreams every resolved prop outcome as a CSV download — ideal for backtesting, model training, and statistical research. Pro tier only.One row per (event, market, bookmaker, outcome) with the line, price, resolution (won/lost/push/void), and actual stat value. PropLine is the only API that offers this — other odds APIs don't resolve props.
Sample row:
event_id,sport_key,commence_time,home_team,away_team,home_score,away_score,market,bookmaker,player_name,outcome_name,line,price_american,price_decimal,resolution,actual_value,resolved_at,customer_token
5885,baseball_mlb,2026-04-19T20:10:00+00:00,Seattle Mariners,Texas Rangers,3,2,pitcher_strikeouts,draftkings,Bryan Woo,Over,6.5,116,2.16,lost,6.0,2026-04-19T23:18:45Z,xxxxxxxxxxxxResponse is text/csv with Content-Disposition: attachment, so curl -O saves straight to a file. Full-season exports can be tens of megabytes — the stream writes as it goes.
Historical depth by tier:
- Pro — last 90 days of resolved outcomes
- Streaming — last 365 days
- Enterprise — full archive, no lookback cap
The effective floor is reflected in the X-PropLine-Export-Window-Start response header. A since value older than your tier's window is silently clamped to the floor. Need deeper history for backtesting? hello@prop-line.com.
Daily call cap by tier:
- Pro — 5 export calls per day
- Streaming — 30 export calls per day
- Enterprise — uncapped
The cap and remaining budget are surfaced on every successful response in the X-PropLine-Export-Daily-Cap and X-PropLine-Export-Daily-Remaining response headers — read those instead of waiting for a 429. Quotas reset at 00:00 UTC. A nightly per-sport reload across our entire catalog fits comfortably under the Pro cap; if your workflow needs more, that is the Enterprise conversation.
Watermarking:
Every row carries a stable customer_token derived from your API key — the same value across all your exports, distinct from any other customer's. The same value is also returned in the X-PropLine-Customer-Token response header. Bulk redistribution of exported data is prohibited under our terms of service; the watermark is how we trace leaks back to their source.
Canary rows:
Every export also appends two synthetic rows whose team and player-name fields begin with the literal prefix (Watermark). The 8-hex token in player_name is HMAC-derived from your API key and the ISO week, so any leaked CSV remains attributable even after the customer_token column is stripped. They appear at the tail of the stream and are easy to filter:
-- Drop canary rows in SQL or pandas
WHERE player_name NOT LIKE '(Watermark)%'Canary rows do not affect any aggregate statistic that excludes them. Full mechanism is disclosed in our watermarking terms.
Full line-movement history (backfill / Enterprise):
GET /v1/exports/odds-history
?sport=baseball_mlb
&market=pitcher_strikeouts # optional
&bookmaker=draftkings # optional
&since=2026-04-01T00:00:00Z # optional, ISO datetime (recorded_at)
&until=2026-05-01T00:00:00Z # optional, ISO datetime (recorded_at)Streams the raw odds tick history — every recorded snapshot (price + line, per book, including period markets), one row per (outcome, snapshot) — not just the closing line. This is the bulk firehose that no subscription tier can pull: Pro and Streaming get per-event /odds/history, but the bulk export is exclusive to the one-time Historical Backfill pass and Enterprise. The pass covers a trailing 2-year lookback (Enterprise unbounded); uncapped calls. Same customer_token watermark + canary rows as the resolved-props export.
Columns:
event_id,sport_key,commence_time,home_team,away_team,market,period,bookmaker,player_name,outcome_name,recorded_at,price_american,price_decimal,point,book_updated_at,customer_tokenA full archive runs to gigabytes per sport — page month by month with since/until so each download stays manageable.
Free sample (no API key):
GET /v1/exports/sample
# Returns the last 7 days of MLB pitcher_strikeouts props as CSV.
# Up to 1000 rows. No auth required.The sample endpoint is open to everyone — useful for evaluating the data shape before upgrading.
Available Markets
| Market Key | Description | Sport |
|---|---|---|
| h2h | Moneyline | All |
| spreads | Point Spread / Run Line | All |
| totals | Over/Under (Game Total) | All |
| pitcher_strikeouts | Pitcher Total Strikeouts | MLB |
| pitcher_earned_runs | Pitcher Earned Runs Allowed | MLB |
| pitcher_hits_allowed | Pitcher Hits Allowed | MLB |
| batter_hits | Batter Total Hits | MLB |
| batter_home_runs | Batter Home Runs | MLB |
| batter_rbis | Batter RBIs | MLB |
| batter_total_bases | Batter Total Bases | MLB |
| batter_stolen_bases | Batter Stolen Bases | MLB |
| batter_walks | Batter Walks | MLB |
| batter_singles | Batter Singles | MLB |
| batter_doubles | Batter Doubles | MLB |
| batter_runs | Batter Runs Scored | MLB |
| pitcher_outs | Pitcher Outs (Innings Proxy) | MLB |
| batter_2plus_hits | Player to Record 2+ Hits | MLB |
| batter_2plus_home_runs | Player to Hit 2+ Home Runs | MLB |
| batter_2plus_rbis | Player to Record 2+ RBIs | MLB |
| batter_3plus_rbis | Player to Record 3+ RBIs | MLB |
| player_points | Player Total Points | NBA |
| player_rebounds | Player Rebounds | NBA |
| player_assists | Player Assists | NBA |
| player_threes | Player Three-Pointers Made | NBA |
| player_steals | Player Steals | NBA |
| player_blocks | Player Blocks | NBA |
| player_turnovers | Player Turnovers | NBA |
| player_points_rebounds_assists | Points + Rebounds + Assists | NBA |
| player_double_double | Player Double-Double | NBA |
| player_goals | Player Goals | NHL |
| player_shots_on_goal | Player Shots on Goal | NHL |
| goalie_saves | Goalie Saves | NHL |
| player_blocked_shots | Player Blocked Shots | NHL |
| anytime_goal_scorer | Anytime Goal Scorer | Soccer |
| first_goal_scorer | First Goal Scorer | Soccer |
| both_teams_to_score | Both Teams to Score | Soccer |
| double_chance | Double Chance | Soccer |
| draw_no_bet | Draw No Bet | Soccer |
| correct_score | Correct Score | Soccer |
| total_corners | Total Corners (O/U) | Soccer |
| corners_spread | Corners Handicap (team spread on corner count) | Soccer |
| team_corners | Team Corners O/U (per-team corner total) | Soccer |
| total_cards | Total Cards | Soccer |
| team_cards | Team Cards O/U (per-team card total) | Soccer |
| 2plus_goals | Player to Score 2+ Goals | Soccer |
| player_assists | Player to Assist a Goal | Soccer |
| player_2plus_assists | Player to Assist 2+ Goals | Soccer |
| player_cards | Player to Be Shown a Card | Soccer |
| goal_or_assist | Player to Score or Assist | Soccer |
| total_rounds | Total Rounds | UFC / Boxing |
| fight_distance | Fight Goes the Distance | UFC / Boxing |
| round_betting | Round Betting | UFC |
| fight_winner | Fight Winner | Boxing |
| fight_outcome | Fight Outcome (KO/TKO/Decision) | Boxing |
Alt lines included: Player prop markets include alternate lines automatically. Query pitcher_strikeouts to get both the primary Over/Under line and alt lines (3+, 5+, 6+ strikeouts etc.) in a single response. Alt spreads, alt totals, and team totals are also included.
Error Codes
| Status | Description |
|---|---|
| 401 | Missing or invalid API key |
| 404 | Sport or event not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |