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:

  1. Get your API key from the signup form
  2. 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:

Python SDK
pip install propline
Node / TS SDK
npm install propline
CLI new
npm install -g propline-cli
Tables in your terminal — GitHub
MCP server
npx -y propline-mcp
Claude Desktop / Code · GitHub

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.

KeyBookCoverage
bovadaBovadaAll 38 sports — game lines + full player props
draftkingsDraftKingsMLB, NBA, NHL, NFL, NCAAF + 9 soccer leagues — game lines + player props (NFL/NCAAF game lines now; player props at preseason)
fanduelFanDuelMLB, NBA, NHL, NFL, NCAAF + 9 soccer leagues — game lines + player props (NFL/NCAAF game lines now; player props at preseason)
betmgmBetMGMMLB, NBA, 17 soccer leagues — game lines + MLB player props (pitcher/batter)
betriversBetRiversMLB, NBA, NHL, 6 soccer leagues — full prop suite incl. NHL Player Points tiers, NBA double/triple-double YES, soccer To Score or Assist
pinnaclePinnacleMLB (game lines + props), NBA/NHL/NFL + 27 soccer leagues (game lines, goalie saves) — sharpest US-facing book
unibetUnibetMLB/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)
onexbet1xBetMLB, NBA, WNBA, NHL + 13 soccer leagues — game lines (h2h, spreads, totals)
tab_auTAB (Australia)MLB, NBA, WNBA, NHL + 13 soccer leagues — game lines (h2h, spreads, totals). Australia's largest licensed wagering operator.
prizepicksPrizePicks (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)
underdogUnderdog 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
kalshiKalshi (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)
polymarketPolymarket (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)
matchbookMatchbook (back/lay exchange)MLB, NBA, NHL + 17 soccer leagues + tennis + boxing — game lines (h2h, totals, spreads). Best back price per runner.
smarketsSmarkets (back/lay exchange)MLB, NBA, NHL + 13 soccer leagues — Match Winner + alt-total + alt-handicap lines. UK exchange with best back price per contract.
novigNovig (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-event lastModified); BetRivers, DraftKings, FanDuel, PrizePicks, Underdog, Kalshi, and Polymarket all return null.
  • book_version (market version counter) — a monotonic integer the book bumps on every market update. Today only Pinnacle exposes one (`market.version`); other books return null. 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

MethodEndpointDescription
GET/sportsList available sports
GET/sports/{sport}/eventsList upcoming events
GET/sports/{sport}/oddsBulk odds (game lines)
GET/sports/{sport}/events/{id}/oddsEvent odds + player props
GET/sports/{sport}/events/{id}/odds/historyHistorical line movement — period filters, downsample, change-only (Hobby+)
GET/sports/{sport}/events/{id}/odds/closingClosing line per (book, market, outcome) — CLV helper (Hobby+)
GET/sports/{sport}/scoresGame scores & status
GET/sports/baseball_mlb/grand-salamiSynthetic daily Grand Salami (total runs + per-book line)
GET/sports/hockey_nhl/daily-goals-totalSynthetic daily NHL goals total (total goals + per-book line)
GET/sports/{sport}/events/{id}/resultsResolved prop outcomes (Pro)
GET/sports/{sport}/players/{name}/historyPlayer prop history with resolution (Pro)
GET/sports/{sport}/players/{name}/trendsPlayer hit-rate trends (L5/L10/L20/L50) (Pro)
GET/sports/{sport}/events/{id}/evCross-book +EV with no-vig fair lines (Pro)
GET/sports/{sport}/futuresFutures markets — championship winner, MVP, etc.
GET/sports/{sport}/events/{id}/statsRaw player/team stats from box scores
GET/exports/resolved-propsBulk CSV export of resolved props + closing lines (Pro)
GET/exports/odds-historyBulk CSV of the full line-movement tick history (Backfill / Enterprise)
GET/exports/sampleFree public CSV sample — last 7 days MLB K props

List Sports

GET /v1/sports

Returns all available sports with their current status.

Response:

[
  {
    "key": "baseball_mlb",
    "title": "MLB",
    "active": true
  }
]

List Events

GET /v1/sports/{sport_key}/events

Returns 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,totals

Returns 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_runs

This 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 buckets

Full 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 to commence_time. Forms: -3h, -30m, -90s, 0. Mutually exclusive with the absolute counterpart.
  • interval — downsample to one snapshot per bucket. One of 30s, 1m, 5m, 15m, 30m, 1h. We pick the last snapshot in each bucket.
  • changes_only — when true, 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_strikeouts

The 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=all

Canonical period codes

CodeMeaningApplies to
q1, q2, q3, q4QuartersNBA, WNBA, NCAAB, NFL, NCAAF
h1, h2HalvesBasketball, football, soccer
p1, p2, p3PeriodsNHL
i1 … i9InningsMLB
f3, f5, f7First N inningsMLB

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=3

Returns 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-22

Synthetic 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-24

Synthetic 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_hits

Returns 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   # optional

For 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 100

Returns 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.

Resolution Coverage (Free)

GET /v1/markets/resolution-summary
    ?days=30   # 1-90, default 30

Aggregated 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}/futures

Season-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}/stats

Returns 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 datetime

Streams 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,xxxxxxxxxxxx

Response 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_token

A 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 KeyDescriptionSport
h2hMoneylineAll
spreadsPoint Spread / Run LineAll
totalsOver/Under (Game Total)All
pitcher_strikeoutsPitcher Total StrikeoutsMLB
pitcher_earned_runsPitcher Earned Runs AllowedMLB
pitcher_hits_allowedPitcher Hits AllowedMLB
batter_hitsBatter Total HitsMLB
batter_home_runsBatter Home RunsMLB
batter_rbisBatter RBIsMLB
batter_total_basesBatter Total BasesMLB
batter_stolen_basesBatter Stolen BasesMLB
batter_walksBatter WalksMLB
batter_singlesBatter SinglesMLB
batter_doublesBatter DoublesMLB
batter_runsBatter Runs ScoredMLB
pitcher_outsPitcher Outs (Innings Proxy)MLB
batter_2plus_hitsPlayer to Record 2+ HitsMLB
batter_2plus_home_runsPlayer to Hit 2+ Home RunsMLB
batter_2plus_rbisPlayer to Record 2+ RBIsMLB
batter_3plus_rbisPlayer to Record 3+ RBIsMLB
player_pointsPlayer Total PointsNBA
player_reboundsPlayer ReboundsNBA
player_assistsPlayer AssistsNBA
player_threesPlayer Three-Pointers MadeNBA
player_stealsPlayer StealsNBA
player_blocksPlayer BlocksNBA
player_turnoversPlayer TurnoversNBA
player_points_rebounds_assistsPoints + Rebounds + AssistsNBA
player_double_doublePlayer Double-DoubleNBA
player_goalsPlayer GoalsNHL
player_shots_on_goalPlayer Shots on GoalNHL
goalie_savesGoalie SavesNHL
player_blocked_shotsPlayer Blocked ShotsNHL
anytime_goal_scorerAnytime Goal ScorerSoccer
first_goal_scorerFirst Goal ScorerSoccer
both_teams_to_scoreBoth Teams to ScoreSoccer
double_chanceDouble ChanceSoccer
draw_no_betDraw No BetSoccer
correct_scoreCorrect ScoreSoccer
total_cornersTotal Corners (O/U)Soccer
corners_spreadCorners Handicap (team spread on corner count)Soccer
team_cornersTeam Corners O/U (per-team corner total)Soccer
total_cardsTotal CardsSoccer
team_cardsTeam Cards O/U (per-team card total)Soccer
2plus_goalsPlayer to Score 2+ GoalsSoccer
player_assistsPlayer to Assist a GoalSoccer
player_2plus_assistsPlayer to Assist 2+ GoalsSoccer
player_cardsPlayer to Be Shown a CardSoccer
goal_or_assistPlayer to Score or AssistSoccer
total_roundsTotal RoundsUFC / Boxing
fight_distanceFight Goes the DistanceUFC / Boxing
round_bettingRound BettingUFC
fight_winnerFight WinnerBoxing
fight_outcomeFight 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

StatusDescription
401Missing or invalid API key
404Sport or event not found
429Rate limit exceeded
500Internal server error