{
  "openapi": "3.1.0",
  "info": {
    "title": "PropLine \u2014 Player Props & Sports Betting Odds API",
    "version": "1.2.0",
    "description": "Real-time player prop betting lines and game odds across 54 sports from 25 books \u2014 14 sportsbooks (BetMGM, BetRivers, Bovada, DraftKings, FanDuel, Pinnacle, Unibet, 1xBet, TAB AU, ReBet, BetUS, BetOnline.ag, LowVig.ag, MyBookie.ag), 4 DFS providers (PrizePicks, Underdog, Sleeper, Dabble), 3 prediction-market exchanges (Kalshi, Polymarket, DraftKings Predictions), and 4 betting exchanges (Matchbook, Smarkets, Novig, ProphetX). Includes prop resolution against actual box-score stats, historical line movement with book-published timestamps, cross-book +EV with no-vig fair lines, an EV calculator for prices at books we don't carry, period-market filtering (?period=q1|h1|p1|f5|map1|s1|g1) on every odds endpoint, futures markets, and bulk CSV exports. Responses are the-odds-api compatible for drop-in migration. Every authenticated response carries live quota headers (X-Daily-Limit, X-Daily-Used, X-Daily-Remaining, X-Daily-Reset \u2014 unix seconds at the 00:00 UTC reset) so usage can be tracked programmatically without a dashboard. Standard rate-limit headers are sent alongside them (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset \u2014 seconds until reset \u2014 and RateLimit-Policy, plus the X-RateLimit-* spelling), so a generic client can self-throttle; both 429 types carry Retry-After. Versioning is in the URL path and anything deprecated keeps serving for at least 12 months with RFC 8594 Deprecation and Sunset headers (https://prop-line.com/api-versioning).",
    "contact": {
      "name": "PropLine",
      "url": "https://prop-line.com",
      "email": "support@prop-line.com"
    }
  },
  "paths": {
    "/v1/sports": {
      "get": {
        "tags": [
          "Sports"
        ],
        "summary": "List Sports",
        "description": "List all available sports.",
        "operationId": "list_sports_v1_sports_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SportOut"
                  },
                  "type": "array",
                  "title": "Response List Sports V1 Sports Get"
                }
              }
            }
          }
        },
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ]
      }
    },
    "/v1/sports/{sport_key}/events": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "List Events",
        "description": "List upcoming events for a sport (no odds \u2014 free endpoint).",
        "operationId": "list_events_v1_sports__sport_key__events_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EventOut"
                  },
                  "title": "Response List Events V1 Sports  Sport Key  Events Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/{sport_key}/odds": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "List Odds",
        "description": "Bulk odds for a sport. Filter by market keys (comma-separated).",
        "operationId": "list_odds_v1_sports__sport_key__odds_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "h2h",
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param.",
            "example": "draftkings,fanduel"
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Game-period filter. Omitted = full-game markets only (backwards-compat default). Pass canonical codes like 'q1', 'h1', 'p1', 'i6', 'f5', 'map1', 's1' (sets \u2014 tennis / volleyball), 'g1' (games \u2014 table tennis / badminton), comma-separated for multiple, or 'all' to include every period.",
            "schema": {
              "type": "string",
              "example": "q1"
            }
          },
          {
            "name": "includeLinks",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, adds a `link` field \u2014 the book's public event-page URL (plain navigation, no affiliate tagging) \u2014 per bookmaker block (odds endpoints) or per price row (/best-line). Links ship for Bovada, DraftKings, FanDuel, BetMGM, Kalshi, Polymarket and Smarkets; other books return null. Matches the-odds-api's includeLinks param. It also adds an `app_link` field (mobile app-open deep link; ProphetX only today, null elsewhere)."
          },
          {
            "name": "includeBookIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, adds `book_event_id` per bookmaker block and `book_outcome_id` per outcome \u2014 each book's OWN identifiers for the event and the priced selection. Use these to join PropLine rows onto a book's native feed by id instead of matching on team names, players and lines. Kalshi ships both (event ticker + per-contract market ticker, e.g. KXMLBGAME-26AUG08NYYBOS-NYY); Bovada, DraftKings, FanDuel, BetMGM, Pinnacle, Polymarket, Smarkets, Novig, Matchbook, Sleeper, Dabble, ReBet, 1xBet, TAB AU and the Kambi books (BetRivers/Unibet) ship event ids. Books without a stable id return null. NB a two-sided market can share one book_outcome_id across both legs (a Kalshi contract is binary \u2014 Over/Under are its YES/NO sides); the outcome's `name` says which side. PropLine-specific, not a the-odds-api param."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EventOddsOut"
                  },
                  "title": "Response List Odds V1 Sports  Sport Key  Odds Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/odds": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "Get Event Odds",
        "description": "Get odds for a single event \u2014 supports player prop markets.\nThis is where the real value is.",
        "operationId": "get_event_odds_v1_sports__sport_key__events__event_id__odds_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "pitcher_strikeouts,batter_hits,batter_home_runs",
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param.",
            "example": "draftkings,fanduel"
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Game-period filter. Omitted = full-game markets only. Canonical codes ('q1', 'h1', 'p1', 'i6', 'f5', 'map1', 's1', 'g1'), comma-separated, or 'all'.",
            "schema": {
              "type": "string",
              "example": "q1"
            }
          },
          {
            "name": "includeLinks",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, adds a `link` field \u2014 the book's public event-page URL (plain navigation, no affiliate tagging) \u2014 per bookmaker block (odds endpoints) or per price row (/best-line). Links ship for Bovada, DraftKings, FanDuel, BetMGM, Kalshi, Polymarket and Smarkets; other books return null. Matches the-odds-api's includeLinks param. It also adds an `app_link` field (mobile app-open deep link; ProphetX only today, null elsewhere)."
          },
          {
            "name": "includeBookIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, adds `book_event_id` per bookmaker block and `book_outcome_id` per outcome \u2014 each book's OWN identifiers for the event and the priced selection. Use these to join PropLine rows onto a book's native feed by id instead of matching on team names, players and lines. Kalshi ships both (event ticker + per-contract market ticker, e.g. KXMLBGAME-26AUG08NYYBOS-NYY); Bovada, DraftKings, FanDuel, BetMGM, Pinnacle, Polymarket, Smarkets, Novig, Matchbook, Sleeper, Dabble, ReBet, 1xBet, TAB AU and the Kambi books (BetRivers/Unibet) ship event ids. Books without a stable id return null. NB a two-sided market can share one book_outcome_id across both legs (a Kalshi contract is binary \u2014 Over/Under are its YES/NO sides); the outcome's `name` says which side. PropLine-specific, not a the-odds-api param."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventOddsOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/markets": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "List Event Markets",
        "description": "List available market types for a specific event.\nUseful for discovering what props are available before requesting odds.",
        "operationId": "list_event_markets_v1_sports__sport_key__events__event_id__markets_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/odds/history": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "Get Event Odds History",
        "description": "Historical odds movement for a single event.\nPro / Streaming / Enterprise: full snapshot history.\nFree tier: redacted (shows structure and count).\n\nDepth is tier-gated by event age: Pro = events from the last 90 days, Streaming = 365 days, Enterprise = unlimited. Events older than the tier window return the redacted shape (empty snapshots + `upgrade_url`)\u00a0\u2014 same envelope as the free-tier redaction, so no schema fork.",
        "operationId": "get_event_odds_history_v1_sports__sport_key__events__event_id__odds_history_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "pitcher_strikeouts,batter_hits",
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param.",
            "example": "draftkings,fanduel"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "ISO timestamp; only include snapshots at or after this time. Mutually exclusive with relative_from.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "ISO timestamp; only include snapshots at or before this time. Mutually exclusive with relative_to.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "relative_from",
            "in": "query",
            "required": false,
            "description": "Offset relative to commence_time, e.g. '-3h', '-30m', '-90s'. Mutually exclusive with `from`.",
            "schema": {
              "type": "string",
              "example": "-3h"
            }
          },
          {
            "name": "relative_to",
            "in": "query",
            "required": false,
            "description": "Offset relative to commence_time, e.g. '-1m' or '0' for commence_time itself. Mutually exclusive with `to`.",
            "schema": {
              "type": "string",
              "example": "0"
            }
          },
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "description": "Downsample to one snapshot per bucket; latest snapshot in each bucket wins.",
            "schema": {
              "type": "string",
              "enum": [
                "30s",
                "1m",
                "5m",
                "15m",
                "30m",
                "1h"
              ]
            }
          },
          {
            "name": "changes_only",
            "in": "query",
            "required": false,
            "description": "When true, drop snapshots whose (price, point) match the previous one. The opening line is always kept.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Game-period filter. Omitted = full-game markets only. Canonical codes ('q1', 'h1', 'p1', 'i6', 'f5', 'map1', 's1', 'g1'), comma-separated, or 'all'.",
            "schema": {
              "type": "string",
              "example": "q1"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventHistoryOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/odds/closing": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "Opening & closing lines (CLV)",
        "description": "Opening and closing line per (book, market, outcome).\n\nClosing = the last snapshot at or before commence_time \u2014 the canonical line CLV-tracking tools measure against. Opening = the first snapshot in the same 14-day pre-kickoff window. Returning both ends in one call is what makes this a complete CLV helper: on spreads and totals the point moves as much as the price (-3 -110 -> -3.5 -105), so `opening_point`/`point` matter as much as the prices.\n\nHobby+ gets full data; free tier is redacted (structure only). Same per-tier event-age cap as /odds/history.",
        "operationId": "get_event_odds_closing_v1_sports__sport_key__events__event_id__odds_closing_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "h2h,spreads,totals",
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param.",
            "example": "draftkings,fanduel"
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Game-period filter. Omitted = full-game markets only. Canonical codes ('q1', 'h1', 'p1', 'i6', 'f5', 'map1', 's1', 'g1'), comma-separated, or 'all'.",
            "schema": {
              "type": "string",
              "example": "q1"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventClosingOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/futures": {
      "get": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "List Futures",
        "description": "List futures markets for a sport \u2014 championship winner, MVP,\ndivision winner, etc. One row per (futures event, book, market) with\nevery team or player priced. Free tier; pulled from each book's\nfutures feed (Bovada today). Order is by event commence_time\n(typically season-end) ascending.",
        "operationId": "list_futures_v1_sports__sport_key__futures_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FuturesEventOut"
                  },
                  "title": "Response List Futures V1 Sports  Sport Key  Futures Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/ev": {
      "get": {
        "tags": [
          "+EV"
        ],
        "summary": "Get Event Ev",
        "description": "Compute cross-book +EV for a single event.\n\n`markets` is an optional comma-separated filter. If omitted, every\nmarket on the event is evaluated. Each market line that has Pinnacle\n(preferred) or Bovada (fallback) coverage gets a no-vig fair price\nand an EV% per book.\n\n`bookmakers` is an optional comma-separated book-key filter \u2014 shop only the books you hold accounts at. It narrows the returned prices, never the anchor.\n\nThe anchor is chosen per line and always named: every line carries `fair_source`, and the response carries `fair_source_default` with the fallback order (pinnacle \u2192 polymarket \u2192 kalshi \u2192 bovada). One response routinely mixes several anchors, so read `fair_source` per line.",
        "operationId": "get_event_ev_v1_sports__sport_key__events__event_id__ev_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Bookmakers"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param. NB it narrows the PRICES only, never the fair-line anchor: bookmakers=draftkings still returns DraftKings EV% measured against Pinnacle. Lines where none of the requested books quote a price are omitted."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventEvOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/ev/calc": {
      "get": {
        "tags": [
          "+EV"
        ],
        "summary": "Calc Event Ev",
        "description": "Calculate EV% for a user-supplied price against the event's no-vig\nfair anchor.\n\nUseful when you bet at a book PropLine doesn't carry directly\n(Caesars, BetMGM, Fanatics, BetUS, Hard Rock, etc.). The fair line\nis derived from the same Pinnacle-preferred anchor as the bulk\n`/ev` endpoint, so the math is identical \u2014 you're just plugging in\na price we don't ingest. Returns 404 with the available outcome\nnames when the (market, point, name) tuple doesn't match any\nfair-anchored line on the event.\n\nPro tier required.",
        "operationId": "calc_event_ev_v1_sports__sport_key__events__event_id__ev_calc_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "market",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Market key, e.g. 'h2h', 'spreads', 'totals', 'pitcher_strikeouts'.",
              "title": "Market"
            },
            "description": "Market key, e.g. 'h2h', 'spreads', 'totals', 'pitcher_strikeouts'."
          },
          {
            "name": "name",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Outcome name. For h2h/spreads: team name. For totals/props: 'Over' or 'Under'.",
              "title": "Name"
            },
            "description": "Outcome name. For h2h/spreads: team name. For totals/props: 'Over' or 'Under'."
          },
          {
            "name": "price",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "American odds at your book, e.g. -118 or +145.",
              "title": "Price"
            },
            "description": "American odds at your book, e.g. -118 or +145."
          },
          {
            "name": "point",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Line/point for spreads, totals, and player props. Omit for h2h. For spreads, sign matters: e.g. -1.5 for the favorite.",
              "title": "Point"
            },
            "description": "Line/point for spreads, totals, and player props. Omit for h2h. For spreads, sign matters: e.g. -1.5 for the favorite."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Player name for player-prop markets; empty for game-line markets.",
              "default": "",
              "title": "Description"
            },
            "description": "Player name for player-prop markets; empty for game-line markets."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvCalcOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/best-line": {
      "get": {
        "tags": [
          "+EV"
        ],
        "summary": "Get Event Best Line",
        "description": "Cross-book best-line lookup for a single event.\n\nFor each (market, player, line) tuple on the event, returns the\nsingle best American price across every comparable book PropLine\ningests, with the book name attached and an `all_prices` array\nsorted best-first (one row per book, each with `last_update`) so\nconsumers can render runner-ups without a second request.\n\n`markets` is an optional comma-separated filter (e.g.\n`markets=h2h,spreads,pitcher_strikeouts`). When omitted, every\nmarket on the event is included. `bookmakers` is an optional\ncomma-separated book-key filter (the-odds-api-compatible) \u2014 shop\nonly the books you hold accounts at.\n\nDFS pick'em books (PrizePicks, Sleeper, Dabble) are excluded \u2014\ntheir quotes aren't independently bettable payouts; Underdog is\nincluded only at its clean two-way lines (payout_multiplier ==\n1.0). Companion to `/ev`: best-line tells you which book has the\nhighest payout right now; +EV tells you whether that price beats a\nsharp no-vig fair line.\n\nHobby tier or higher sees prices. Free tier gets a redacted\nteaser: the full structure \u2014 every line, side, book identity, and\nthe best-first ranking \u2014 with every price nulled, plus\n`redacted: true` and an `upgrade_url`.",
        "operationId": "get_event_best_line_v1_sports__sport_key__events__event_id__best_line_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all comparable books. Matches the-odds-api's `bookmakers` param.",
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Bookmakers"
            }
          },
          {
            "name": "includeLinks",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, adds a `link` field \u2014 the book's public event-page URL (plain navigation, no affiliate tagging) \u2014 per bookmaker block (odds endpoints) or per price row (/best-line). Links ship for Bovada, DraftKings, FanDuel, BetMGM, Kalshi, Polymarket and Smarkets; other books return null. Matches the-odds-api's includeLinks param. It also adds an `app_link` field (mobile app-open deep link; ProphetX only today, null elsewhere)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventBestLineOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/scores": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "List Scores",
        "description": "Game scores and status for recent events (last N days).\nFree tier \u2014 no Pro required.",
        "operationId": "list_scores_v1_sports__sport_key__scores_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "days_from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 3,
              "title": "Days From"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ScoreOut"
                  },
                  "title": "Response List Scores V1 Sports  Sport Key  Scores Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/baseball_mlb/grand-salami": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "MLB Grand Salami",
        "description": "Synthetic daily Grand Salami \u2014 total runs scored across all MLB games on a given UTC date, plus each book's implied Grand Salami line (sum of per-game primary totals across our MLB books). No retail book quotes this as a single market. Free tier. Default date is today (UTC).",
        "operationId": "mlb_grand_salami_v1_sports_baseball_mlb_grand_salami_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "",
              "title": "Date (YYYY-MM-DD UTC)"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrandSalamiOut"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date format"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/hockey_nhl/daily-goals-total": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "NHL Daily Goals Total",
        "description": "Hockey's equivalent of the MLB Grand Salami \u2014 total goals scored across all NHL games on a given UTC date (incl. OT/SO), plus each book's implied Daily Goals Total line (sum of per-game primary totals across our NHL books). No retail book quotes this as a single market. Free tier. Default date is today (UTC).",
        "operationId": "nhl_daily_goals_total_v1_sports_hockey_nhl_daily_goals_total_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "",
              "title": "Date (YYYY-MM-DD UTC)"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyGoalsTotalOut"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date format"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/stats": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "Get Event Stats",
        "description": "Actual player/team stats from box scores (book-agnostic).\nUse these to resolve props against any sportsbook's lines.\nLive during games for major US sports (MLB + WNBA now; NFL, NCAAF, NBA, NHL at season start): while status is in_progress, stats refresh ~every 90 seconds with cumulative in-game values; at final they are the official box score. Other sports populate at game completion.\nFree tier \u2014 no Pro required.",
        "operationId": "get_event_stats_v1_sports__sport_key__events__event_id__stats_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "stat_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "",
              "title": "Stat Type"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventStatsOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/movement": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "Get Line Movement & Steam",
        "description": "Line movement derived from the snapshot tick history. Per (book, market, outcome): opening line, latest line, and the implied-probability / point shift between them. The steam[] array flags outcomes multiple books moved in the same direction \u2014 the sharp-money signal, computed across all 25 books. Hobby+ full; free tier redacted.",
        "operationId": "get_event_movement_v1_sports__sport_key__events__event_id__movement_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "h2h,spreads,totals",
              "title": "Markets"
            }
          },
          {
            "name": "bookmakers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bookmaker keys (e.g. 'draftkings,fanduel'). Omitted = all books. Matches the-odds-api's bookmakers param.",
            "example": "draftkings,fanduel"
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Period"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventMovementOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/context": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "Get Game Context",
        "description": "Conditions a game is played under: probable starting pitchers, confirmed-lineup flag, the home-plate umpire, and first-pitch weather (outdoor / open-roof venues).\nThe same context is embedded in the /results response so every graded prop carries the conditions it settled against.\nFree tier. MLB today; weather extends to other outdoor sports next. 404 when no context is on file yet.",
        "operationId": "get_event_context_v1_sports__sport_key__events__event_id__context_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GameContextOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/events/{event_id}/results": {
      "get": {
        "tags": [
          "Scores & Results"
        ],
        "summary": "Get Event Results",
        "description": "Resolved prop outcomes with actual player stats.\nPro / Streaming / Enterprise: full resolution data.\nFree tier: redacted (shows structure but hides results).",
        "operationId": "get_event_results_v1_sports__sport_key__events__event_id__results_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "title": "Event Id"
            }
          },
          {
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "",
              "title": "Markets"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventResultOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On an event id that previously worked, the event was likely merged into a canonical duplicate (the same fixture posted by multiple books under different team-name spellings). Merged ids resolve automatically and return the canonical event with a 200 \u2014 its `id` field is the id to store. A persistent 404 means re-fetch the event from /v1/sports/{sport}/events and use the current id."
          }
        }
      }
    },
    "/v1/sports/{sport_key}/players/{player_name}/history": {
      "get": {
        "tags": [
          "Players"
        ],
        "summary": "Get Player History",
        "description": "Resolved prop history for a player in a given market.\n\nReturns one entry per (event, bookmaker) pair with line + prices +\nresolution + actual value.\n\nPro / Streaming / Enterprise: full data.\nFree tier: structure only \u2014 resolution + actual_value redacted.",
        "operationId": "get_player_history_v1_sports__sport_key__players__player_name__history_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "player_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Player Name"
            }
          },
          {
            "name": "market",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Market key, e.g. pitcher_strikeouts",
              "title": "Market"
            },
            "description": "Market key, e.g. pitcher_strikeouts"
          },
          {
            "name": "bookmaker",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional bookmaker filter",
              "default": "",
              "title": "Bookmaker"
            },
            "description": "Optional bookmaker filter"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlayerHistoryOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sports/{sport_key}/players/{player_name}/trends": {
      "get": {
        "tags": [
          "Players"
        ],
        "summary": "Get Player Trends",
        "description": "Aggregated hit-rate trends for a player \u2014 \"did X go over in N of his last M games?\" \u2014 across every market they have graded history in.\n\nFor each market: over/under/push splits across the last 5 / 10 / 20 / 50 graded games, the current over/under streak, average actual stat, and the most recent line. The verdict each game compares the player's real (book-agnostic) stat against one reference book's posted line; pushes are excluded from the over_pct denominator.\n\nDerived entirely from PropLine's prop resolution \u2014 the-odds-api has no equivalent. Paid tiers (Hobby and above): full data. Free tier: market list + graded-game counts, with the rates redacted.",
        "operationId": "get_player_trends_v1_sports__sport_key__players__player_name__trends_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sport Key"
            },
            "description": "Sport key. the-odds-api names are accepted as aliases (americanfootball_nfl -> football_nfl, icehockey_nhl -> hockey_nhl, soccer_spain_la_liga -> soccer_la_liga, ...), but only where the competition is identical; otherwise the request returns 404 with a structured body carrying `reason` and `did_you_mean`. Canonical list: GET /v1/sports."
          },
          {
            "name": "player_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Player Name"
            }
          },
          {
            "name": "market",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional market key to filter to one market",
              "default": "",
              "title": "Market"
            },
            "description": "Optional market key to filter to one market"
          },
          {
            "name": "dfs_odds_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "standard",
                "goblin",
                "demon"
              ],
              "default": "",
              "title": "DFS Odds Type"
            },
            "description": "Optional PrizePicks pick-em flavor filter: 'standard', 'goblin', or 'demon'. When set, trends are computed against that flavor's PrizePicks line only (e.g. compare a player's goblin-line hit-rate vs his standard-line trend). Omitted = cross-book behavior (reference line from the preferred-book list, flavor ignored). PrizePicks flavor tagging began 2026-06-16, so per-flavor trends only have depth from that date forward."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlayerTrendsOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/exports/resolved-props": {
      "get": {
        "tags": [
          "Exports"
        ],
        "summary": "Export Resolved Props",
        "description": "Stream resolved prop outcomes as CSV. Pro+ tier required.\n\nOne row per (event, market, bookmaker, outcome). Includes the line,\nprice, resolution (won/lost/push/void), and actual stat value \u2014 the\nexact data model builders need for CLV and backtesting. Every row also carries both ends of the line move: the closing line\n(`closing_price` / `closing_point` / `closing_at` = the last snapshot at\nor before commence_time) and the opening line (`opening_price` /\n`opening_point` / `opening_at` = the first snapshot in the 14 days\nbefore kickoff). That makes a full CLV study one download rather than\none history call per event, and it is something the-odds-api cannot\noffer since they don't resolve props. Note `closing_point` is distinct\nfrom `line`, which is the outcome's own current point.\n\nNew columns are always appended immediately before `customer_token`, so\npositional parsers written against an earlier column set keep working.\n\nHistorical depth is tier-gated: Pro = last 90 days, Streaming = last\n365 days, Enterprise = unbounded. The effective floor is reflected in\nthe `X-PropLine-Export-Window-Start` response header.\n\nDaily call cap is also tier-gated: Pro = 50/day, Streaming Lite =\n100/day, Streaming = 200/day, Enterprise = uncapped. The cap counts\nwhole calls, not rows, and `sport` is required, so a multi-sport pull\nis one call per sport \u2014 the efficient pattern is one call per sport\nover the widest date range you need. Remaining budget is surfaced on\nevery successful response in the `X-PropLine-Export-Daily-Remaining`\nheader; over-cap calls return 429 with a `Retry-After` set to the\nseconds until 00:00 UTC.\n\nEvery row carries a `dfs_odds_type` column \u2014 the PrizePicks projection\ntier (`standard` / `goblin` / `demon`); blank for traditional\nsportsbooks.\n\nArchive coverage is stated in-band on every response: the `X-PropLine-Archive-Starts` header carries the sport's earliest held date (`none` if the sport has no data yet), and `X-PropLine-Archive-Notice` is set when the requested window ends before the archive begins, meaning the export can only be empty.",
        "operationId": "export_resolved_props_v1_exports_resolved_props_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Sport key (e.g. baseball_mlb). Required.",
              "title": "Sport"
            },
            "description": "Sport key (e.g. baseball_mlb). Required."
          },
          {
            "name": "market",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional market filter, e.g. pitcher_strikeouts",
              "default": "",
              "title": "Market"
            },
            "description": "Optional market filter, e.g. pitcher_strikeouts"
          },
          {
            "name": "bookmaker",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional bookmaker filter",
              "default": "",
              "title": "Bookmaker"
            },
            "description": "Optional bookmaker filter"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime lower bound on resolved_at",
              "title": "Since"
            },
            "description": "ISO datetime lower bound on resolved_at"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime upper bound on resolved_at",
              "title": "Until"
            },
            "description": "ISO datetime upper bound on resolved_at"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/exports/odds-history": {
      "get": {
        "tags": [
          "Exports"
        ],
        "summary": "Export Odds History",
        "description": "Stream the full line-movement time-series as CSV \u2014 every recorded odds snapshot (price + line, per book, including period markets) for every outcome, not just the closing line. One row per (outcome, snapshot).\n\nThis is the raw tick history that no subscription tier can pull in bulk: Pro/Streaming get per-event `/odds/history` and the resolved-props export (closing line only), but the bulk snapshot firehose is exclusive to the one-time Historical Backfill pass and Enterprise. Backfill pass = trailing 2-year lookback (Enterprise unbounded); uncapped calls.\n\nA full all-sport, all-history pull is many GB \u2014 page month-by-month with `since`/`until` to keep any single request bounded.\n\nColumns: 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, dfs_odds_type, customer_token (dfs_odds_type = PrizePicks tier: standard / goblin / demon; blank for sportsbooks).\n\nArchive coverage is stated in-band on every response: the `X-PropLine-Archive-Starts` header carries the sport's earliest held date (`none` if the sport has no data yet), and `X-PropLine-Archive-Notice` is set when the requested window ends before the archive begins, meaning the export can only be empty.",
        "operationId": "export_odds_history_v1_exports_odds_history_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Sport key (e.g. baseball_mlb). Required.",
              "title": "Sport"
            },
            "description": "Sport key (e.g. baseball_mlb). Required."
          },
          {
            "name": "market",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional market filter, e.g. pitcher_strikeouts",
              "default": "",
              "title": "Market"
            },
            "description": "Optional market filter, e.g. pitcher_strikeouts"
          },
          {
            "name": "bookmaker",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Optional bookmaker filter",
              "default": "",
              "title": "Bookmaker"
            },
            "description": "Optional bookmaker filter"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime lower bound on recorded_at",
              "title": "Since"
            },
            "description": "ISO datetime lower bound on recorded_at"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime upper bound on recorded_at",
              "title": "Until"
            },
            "description": "ISO datetime upper bound on recorded_at"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/exports/sample": {
      "get": {
        "tags": [
          "Exports"
        ],
        "summary": "Export Sample",
        "description": "Public sample: last 7 days of MLB pitcher_strikeouts as CSV.\n\nNo auth required \u2014 this is a SEO/marketing lead magnet. Capped to\nkeep it a taste, not a full dataset. For full access, Pro tier\nusers hit /v1/exports/resolved-props.",
        "operationId": "export_sample_v1_exports_sample_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/markets/hit-rates": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get Market Hit Rates",
        "description": "Per-market daily Over hit rates over the last N days.\n\nResponse shape:\n    {\n      \"days\": 28,\n      \"bookmaker\": \"bovada\",\n      \"markets\": {\n        \"pitcher_strikeouts\": [\n          {\"date\": \"2026-04-01\", \"total\": 14, \"won\": 6},\n          ...\n        ],\n        \"batter_total_bases\": [...],\n        ...\n      }\n    }\n\n`total` and `won` are scoped to graded **Over** outcomes only \u2014 the\nsame denominator the cross-sport accuracy panel uses, so the numbers\nline up. `total` excludes voids; `won` is the subset where the actual\nstat exceeded the line.",
        "operationId": "get_market_hit_rates_v1_markets_hit_rates_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 60,
              "minimum": 1,
              "description": "Look-back window in days",
              "default": 28,
              "title": "Days"
            },
            "description": "Look-back window in days"
          },
          {
            "name": "bookmaker",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Bookmaker to aggregate. Defaults to bovada \u2014 the canonical book for /today.",
              "default": "bovada",
              "title": "Bookmaker"
            },
            "description": "Bookmaker to aggregate. Defaults to bovada \u2014 the canonical book for /today."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/dfs/payouts": {
      "get": {
        "tags": [
          "DFS"
        ],
        "summary": "DFS Payout Schedule + Breakeven",
        "description": "PrizePicks Power Play (all legs must hit) and Flex Play (partial payouts) entry payout schedule for 2-6 legs, plus the per-leg breakeven win probability for each play type and leg count. Pass `?leg_win_prob=0.58` to also get `expected_return` (per $1 staked) and `is_plus_ev` at that assumed per-leg hit rate. Pure reference math \u2014 free for any authenticated key. NOTE (see the `disclaimer` field): these are standard published payouts that PrizePicks can change; demon/goblin per-pick modifiers are NOT in PrizePicks's feed so they are not reflected; breakeven assumes independent legs (real legs are correlated, so treat it as a floor).",
        "operationId": "dfs_payouts_v1_dfs_payouts_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "prizepicks",
              "title": "Platform",
              "description": "DFS platform. Only 'prizepicks' today."
            },
            "description": "DFS platform. Only 'prizepicks' today."
          },
          {
            "name": "leg_win_prob",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "maximum": 1.0,
              "minimum": 0.0,
              "title": "Leg Win Prob",
              "description": "Assumed per-leg win probability. When supplied, each play also returns expected_return and is_plus_ev."
            },
            "description": "Assumed per-leg win probability. When supplied, each play also returns expected_return and is_plus_ev."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "404": {
            "description": "Unknown platform"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/markets/resolution-summary": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get Resolution Summary",
        "description": "Factual volume of graded player props over the last N days.\n\nAggregated counts only (no individual prop data). Every outcome counted here was graded against the real box score \u2014 a moat statement nobody else (the-odds-api, OddsJam) can make at any tier. This is a volume statement, never a profitability one.\n\nResponse shape:\n    {\n      \"days\": 30,\n      \"total_graded\": 812334,\n      \"total_settled\": 798901,\n      \"events_graded\": 4120,\n      \"sports_covered\": 33,\n      \"by_sport\": [{\"sport_key\",\"title\",\"graded\",\"events\"}...],\n      \"top_markets\": [{\"market_key\",\"graded\"}...]\n    }",
        "operationId": "get_resolution_summary_v1_markets_resolution_summary_get",
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 90,
              "minimum": 1,
              "description": "Look-back window in days",
              "default": 30,
              "title": "Days"
            },
            "description": "Look-back window in days"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/clv/grade": {
      "post": {
        "tags": [
          "Events & Odds"
        ],
        "summary": "Grade placed bets against the closing line (CLV)",
        "description": "POST the bets you actually placed; each comes back with its closing line, the de-vigged closing fair probability, CLV, and the graded result once the game settles. Closing line value is the only durable proxy for whether a bettor has edge.\n\nStateless \u2014 nothing is stored.\n\nTwo CLV numbers are returned deliberately. `clv_pct` is price-vs-price: familiar and quotable, but vig-blind. `ev_vs_close_pct` scores your price against the DE-VIGGED close and is the honest one \u2014 a -110 taken into a -105/-115 close beat the price but not the fair line.\n\nThe de-vig uses the sharpest book quoting that line at close (Pinnacle first, then Polymarket / Kalshi / Bovada / Smarkets, falling back to your own book), reported as `fair_source`. De-vigging the book you bet at always returns a negative number because you paid its hold.\n\nMatching 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. Lines match by equality, never nearest-value.\n\nBets on events that have not started carry `closing_is_final: false` and are excluded from the summary averages. Max 500 bets per request.\n\nHobby+ gets full data; free tier is redacted (structure and match verdicts visible, every number nulled).",
        "operationId": "gradeClv",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "maxItems": 500,
                "items": {
                  "type": "object",
                  "required": [
                    "sport_key",
                    "event_id",
                    "market",
                    "bookmaker",
                    "selection",
                    "price"
                  ],
                  "properties": {
                    "ref": {
                      "type": "string",
                      "nullable": true,
                      "description": "Caller-supplied id echoed back, so rows can be aligned without relying on list order."
                    },
                    "sport_key": {
                      "type": "string",
                      "example": "baseball_mlb"
                    },
                    "event_id": {
                      "type": "integer",
                      "example": 150791
                    },
                    "market": {
                      "type": "string",
                      "example": "batter_hits_runs_rbis"
                    },
                    "bookmaker": {
                      "type": "string",
                      "example": "lowvig"
                    },
                    "selection": {
                      "type": "string",
                      "description": "Player name for a prop, team name for a game line.",
                      "example": "Drake Baldwin"
                    },
                    "side": {
                      "type": "string",
                      "nullable": true,
                      "description": "Over/Under for a two-way market; omit for YES-only props.",
                      "example": "Under"
                    },
                    "point": {
                      "type": "number",
                      "nullable": true,
                      "example": 0.5
                    },
                    "period": {
                      "type": "string",
                      "nullable": true,
                      "description": "Canonical period code (q1, h1, p1, f5). Omit for full game."
                    },
                    "price": {
                      "type": "integer",
                      "description": "American odds you took.",
                      "example": 145
                    },
                    "stake": {
                      "type": "number",
                      "nullable": true,
                      "description": "Defaults to 1 unit when computing profit_units."
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Graded bets plus a portfolio summary.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "summary": {
                      "type": "object",
                      "properties": {
                        "bets": {
                          "type": "integer"
                        },
                        "matched": {
                          "type": "integer"
                        },
                        "unmatched": {
                          "type": "integer"
                        },
                        "graded": {
                          "type": "integer"
                        },
                        "pending": {
                          "type": "integer",
                          "description": "Matched bets whose event has not started; excluded from the averages."
                        },
                        "avg_clv_pct": {
                          "type": "number",
                          "nullable": true
                        },
                        "avg_ev_vs_close_pct": {
                          "type": "number",
                          "nullable": true
                        },
                        "beat_close_pct": {
                          "type": "number",
                          "nullable": true
                        },
                        "profit_units": {
                          "type": "number",
                          "nullable": true
                        }
                      }
                    },
                    "bets": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "ref": {
                            "type": "string",
                            "nullable": true
                          },
                          "matched": {
                            "type": "boolean"
                          },
                          "unmatched_reason": {
                            "type": "string",
                            "nullable": true,
                            "enum": [
                              "event_not_found",
                              "no_market_for_key",
                              "no_outcome_for_selection",
                              "ambiguous_selection",
                              "no_closing_snapshot",
                              null
                            ]
                          },
                          "closing_price": {
                            "type": "integer",
                            "nullable": true
                          },
                          "closing_point": {
                            "type": "number",
                            "nullable": true
                          },
                          "closing_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "closing_is_stale": {
                            "type": "boolean"
                          },
                          "closing_is_final": {
                            "type": "boolean"
                          },
                          "fair_source": {
                            "type": "string",
                            "nullable": true
                          },
                          "closing_fair_prob": {
                            "type": "number",
                            "nullable": true
                          },
                          "clv_pct": {
                            "type": "number",
                            "nullable": true
                          },
                          "ev_vs_close_pct": {
                            "type": "number",
                            "nullable": true
                          },
                          "beat_close": {
                            "type": "boolean",
                            "nullable": true
                          },
                          "resolution": {
                            "type": "string",
                            "nullable": true,
                            "enum": [
                              "won",
                              "lost",
                              "push",
                              "void",
                              null
                            ]
                          },
                          "actual_value": {
                            "type": "number",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "redacted": {
                      "type": "boolean"
                    },
                    "upgrade_url": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "More than 500 bets in one request."
          }
        },
        "security": [
          {
            "APIKeyHeader": []
          },
          {
            "APIKeyQuery": []
          }
        ]
      }
    },
    "/v1/freshness": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Per-book data freshness",
        "description": "Last update and staleness in seconds for every book, split by market class (game lines vs player props). Free, no auth. Check it before trusting any book's prices \u2014 a book that has stopped delivering shows here first.",
        "operationId": "getFreshness",
        "responses": {
          "200": {
            "description": "Freshness per bookmaker.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "as_of": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "stale_threshold_seconds": {
                      "type": "integer"
                    },
                    "bookmakers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "market_count": {
                            "type": "integer"
                          },
                          "latest_update": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "staleness_seconds": {
                            "type": "integer"
                          },
                          "is_stale": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": []
      }
    }
  },
  "components": {
    "schemas": {
      "BestLineOut": {
        "description": "One (market_key, player, point) tuple with the best price per side.",
        "properties": {
          "market_key": {
            "type": "string",
            "title": "Market Key"
          },
          "description": {
            "type": "string",
            "description": "Player name (props) or empty string (game lines).",
            "title": "Description"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Shared O/U or h2h line. Null for h2h moneylines.",
            "title": "Point"
          },
          "sides": {
            "additionalProperties": {
              "$ref": "#/components/schemas/BestLineSideOut"
            },
            "type": "object",
            "description": "Map of side name (e.g. \"Over\"/\"Under\" or team name) to best price + alternatives.",
            "title": "Sides"
          }
        },
        "type": "object",
        "required": [
          "market_key",
          "description",
          "point",
          "sides"
        ],
        "title": "BestLineOut"
      },
      "BestLineSideOut": {
        "description": "Best price + every alternative for one side of a market line.",
        "properties": {
          "best": {
            "$ref": "#/components/schemas/BestPriceOut",
            "description": "The highest American price across the books returning a valid quote for this side."
          },
          "all_prices": {
            "items": {
              "$ref": "#/components/schemas/BestPriceOut"
            },
            "type": "array",
            "description": "Every book's price, sorted best-first (descending price), one row per book. DFS pick'em books (PrizePicks, Sleeper, Dabble) are excluded; Underdog only at clean two-way lines (payout_multiplier == 1.0).",
            "title": "All Prices"
          }
        },
        "type": "object",
        "required": [
          "best",
          "all_prices"
        ],
        "title": "BestLineSideOut"
      },
      "BestPriceOut": {
        "description": "A single book's price at a given line.",
        "properties": {
          "book": {
            "type": "string",
            "title": "Book"
          },
          "book_title": {
            "type": "string",
            "title": "Book Title"
          },
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "American odds. Null only on free-tier redacted responses (book identity and ranking stay visible; the price is paid).",
            "title": "Price"
          },
          "last_update": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When this book last refreshed the market carrying this price \u2014 discount stale quotes.",
            "title": "Last Update"
          },
          "link": {
            "description": "Public event-page URL at this book. Only set when the request passed includeLinks=true and the book has a verified URL template.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Link"
          },
          "app_link": {
            "type": "string",
            "nullable": true,
            "description": "Mobile app-open deep link at this book \u2014 opens the book's native app on this fixture (with an app-store fallback for users without the app), vs `link` which is the desktop web event page. Only set when includeLinks=true and the book has a verified app-link template. ProphetX only today (an AppsFlyer OneLink); null for every other book."
          },
          "liquidity": {
            "type": "number",
            "nullable": true,
            "description": "Dollars a bettor can actually stake at the quoted price. Exchange books publishing resting size only (ProphetX today); null for every other book, and for an exchange quote whose size the feed omitted. On a P2P exchange the best price is often a thin offer with only a few dollars behind it \u2014 filter or discount small values before treating the price as bettable. Refreshed every poll cycle independently of price movement; liquidity changes never appear in /odds/history or fire line_movement webhooks."
          }
        },
        "type": "object",
        "required": [
          "book",
          "book_title",
          "price"
        ],
        "title": "BestPriceOut"
      },
      "BookmakerHistoryOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/MarketHistoryOut"
            },
            "type": "array",
            "title": "Markets"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "markets"
        ],
        "title": "BookmakerHistoryOut"
      },
      "BookmakerOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "last_update": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Update"
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/MarketOut"
            },
            "type": "array",
            "title": "Markets"
          },
          "link": {
            "description": "Public event-page URL at this book. Only set when the request passed includeLinks=true and the book has a verified URL template.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Link"
          },
          "app_link": {
            "type": "string",
            "nullable": true,
            "description": "Mobile app-open deep link at this book \u2014 opens the book's native app on this fixture (app-store fallback otherwise), vs `link` which is the desktop web event page. Only set when includeLinks=true and the book has a verified app-link template. ProphetX only today (an AppsFlyer OneLink); null for every other book. PropLine-specific, not a the-odds-api field."
          },
          "book_event_id": {
            "type": "string",
            "nullable": true,
            "description": "This book's own event identifier (Kalshi event ticker, DraftKings/BetMGM numeric event id, Pinnacle matchup id, ...). Only set when the request passed includeBookIds=true and this book publishes a stable id."
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "markets"
        ],
        "title": "BookmakerOut"
      },
      "BookmakerResultOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/ResolvedMarketOut"
            },
            "type": "array",
            "title": "Markets"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "markets"
        ],
        "title": "BookmakerResultOut"
      },
      "EvCalcOut": {
        "properties": {
          "market": {
            "type": "string",
            "title": "Market"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "price": {
            "type": "integer",
            "title": "Price"
          },
          "fair_source": {
            "type": "string",
            "title": "Fair Source"
          },
          "fair_prob": {
            "type": "number",
            "title": "Fair Prob"
          },
          "implied_prob": {
            "type": "number",
            "title": "Implied Prob"
          },
          "ev_pct": {
            "type": "number",
            "title": "Ev Pct"
          },
          "is_plus_ev": {
            "type": "boolean",
            "title": "Is Plus Ev"
          }
        },
        "type": "object",
        "required": [
          "market",
          "name",
          "point",
          "description",
          "price",
          "fair_source",
          "fair_prob",
          "implied_prob",
          "ev_pct",
          "is_plus_ev"
        ],
        "title": "EvCalcOut",
        "description": "User-supplied price evaluated against the event's no-vig fair anchor."
      },
      "EvLineOut": {
        "properties": {
          "market_key": {
            "type": "string",
            "title": "Market Key"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "fair_source": {
            "type": "string",
            "title": "Fair Source"
          },
          "fair_probs": {
            "additionalProperties": {
              "type": "number"
            },
            "type": "object",
            "title": "Fair Probs"
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/EvOutcomeOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "market_key",
          "description",
          "point",
          "fair_source",
          "fair_probs",
          "outcomes"
        ],
        "title": "EvLineOut"
      },
      "EvOutcomeOut": {
        "properties": {
          "book": {
            "type": "string",
            "title": "Book"
          },
          "book_title": {
            "type": "string",
            "title": "Book Title"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "price": {
            "type": "integer",
            "title": "Price"
          },
          "ev_pct": {
            "type": "number",
            "title": "Ev Pct"
          },
          "is_plus_ev": {
            "type": "boolean",
            "title": "Is Plus Ev"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          }
        },
        "type": "object",
        "required": [
          "book",
          "book_title",
          "name",
          "price",
          "ev_pct",
          "is_plus_ev"
        ],
        "title": "EvOutcomeOut"
      },
      "EventBestLineOut": {
        "description": "Cross-book best-line response for one event.",
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "books_considered": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "description": "Books that quoted at least one line on this event. DFS pick'em books (PrizePicks, Sleeper, Dabble) are always excluded.",
            "title": "Books Considered"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/BestLineOut"
            },
            "type": "array",
            "title": "Lines"
          },
          "redacted": {
            "type": "boolean",
            "default": false,
            "description": "True on free-tier responses: structure, book identities, and best-first ranking are visible but every price is nulled.",
            "title": "Redacted"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Set on redacted responses \u2014 where to upgrade for full prices.",
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "books_considered",
          "lines"
        ],
        "title": "EventBestLineOut"
      },
      "EventEvOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "fair_source_default": {
            "type": "string",
            "title": "Fair Source Default"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/EvLineOut"
            },
            "type": "array",
            "title": "Lines"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "fair_source_default",
          "lines"
        ],
        "title": "EventEvOut"
      },
      "EventHistoryOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "live": {
            "type": "boolean",
            "title": "Live",
            "default": false
          },
          "bookmakers": {
            "items": {
              "$ref": "#/components/schemas/BookmakerHistoryOut"
            },
            "type": "array",
            "title": "Bookmakers"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "bookmakers"
        ],
        "title": "EventHistoryOut"
      },
      "ClosingOutcomeOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "closing_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Closing At",
            "description": "recorded_at of the chosen pre-commence snapshot"
          },
          "closing_age_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Closing Age Seconds",
            "description": "Seconds between closing_at and commence_time. Large values mean the book stopped quoting early and this is not a true close."
          },
          "is_stale": {
            "type": "boolean",
            "title": "Is Stale",
            "default": false,
            "description": "True when closing_age_seconds > 600 (10 min before kickoff). Advisory, not a hard filter."
          },
          "opening_price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opening Price",
            "description": "American price of the first snapshot in the 14 days before kickoff."
          },
          "opening_point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opening Point",
            "description": "Line that went with opening_price. On spreads and totals the point moves as much as the price, so both ends are needed for CLV."
          },
          "opening_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opening At",
            "description": "recorded_at of the chosen opening snapshot."
          },
          "opening_age_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opening Age Seconds",
            "description": "Seconds between opening_at and commence_time. The archive starts 2026-04, so for a book/sport we began polling after the line was posted this is 'first observed by us', not the book's true open \u2014 a small value here is the tell."
          },
          "book_updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Updated At"
          },
          "book_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Version"
          },
          "redacted": {
            "type": "boolean",
            "title": "Redacted",
            "default": false
          },
          "dfs_odds_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dfs Odds Type",
            "description": "PrizePicks projection tier (standard/goblin/demon); null for traditional sportsbooks."
          }
        },
        "type": "object",
        "required": [
          "name",
          "description",
          "price",
          "point"
        ],
        "title": "ClosingOutcomeOut"
      },
      "ClosingMarketOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Game-period bucket. Null for full-game markets."
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/ClosingOutcomeOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "description",
          "outcomes"
        ],
        "title": "ClosingMarketOut"
      },
      "ClosingBookmakerOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/ClosingMarketOut"
            },
            "type": "array",
            "title": "Markets"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "markets"
        ],
        "title": "ClosingBookmakerOut"
      },
      "EventClosingOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "bookmakers": {
            "items": {
              "$ref": "#/components/schemas/ClosingBookmakerOut"
            },
            "type": "array",
            "title": "Bookmakers"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "bookmakers"
        ],
        "title": "EventClosingOut"
      },
      "EventOddsOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "live": {
            "type": "boolean",
            "title": "Live",
            "default": false
          },
          "last_update": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Update"
          },
          "bookmakers": {
            "items": {
              "$ref": "#/components/schemas/BookmakerOut"
            },
            "type": "array",
            "title": "Bookmakers"
          },
          "merged_from_event_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "description": "Event ids that were merged INTO this event when duplicate fixtures from different bookmakers were folded into one. Always present (no flag); null for the large majority of events, which have never been merged. Lets a client reconcile a stored id from the response it was already fetching instead of re-requesting every saved id."
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "bookmakers"
        ],
        "title": "EventOddsOut"
      },
      "EventOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "live": {
            "type": "boolean",
            "title": "Live",
            "default": false
          },
          "bookmakers": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/BookmakerOut"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bookmakers"
          },
          "merged_from_event_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "description": "Event ids that were merged INTO this event when duplicate fixtures from different bookmakers were folded into one. Always present (no flag); null for the large majority of events, which have never been merged. Lets a client reconcile a stored id from the response it was already fetching instead of re-requesting every saved id."
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time"
        ],
        "title": "EventOut"
      },
      "EventResultOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "live": {
            "type": "boolean",
            "title": "Live",
            "default": false
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "home_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Score"
          },
          "away_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Away Score"
          },
          "bookmakers": {
            "items": {
              "$ref": "#/components/schemas/BookmakerResultOut"
            },
            "type": "array",
            "title": "Bookmakers"
          },
          "context": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/GameContextOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "status",
          "home_score",
          "away_score",
          "bookmakers"
        ],
        "title": "EventResultOut"
      },
      "MovementOutcomeOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "open_price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Open Price"
          },
          "open_point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Open Point"
          },
          "open_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Open At"
          },
          "latest_price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest Price"
          },
          "latest_point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest Point"
          },
          "latest_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest At"
          },
          "prob_shift": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Prob Shift"
          },
          "point_shift": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point Shift"
          },
          "direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Direction"
          },
          "num_snapshots": {
            "type": "integer",
            "default": 0,
            "title": "Num Snapshots"
          },
          "redacted": {
            "type": "boolean",
            "default": false,
            "title": "Redacted"
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "MovementOutcomeOut"
      },
      "MovementMarketOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "outcomes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MovementOutcomeOut"
            },
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "outcomes"
        ],
        "title": "MovementMarketOut"
      },
      "MovementBookmakerOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MovementMarketOut"
            },
            "title": "Markets"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "markets"
        ],
        "title": "MovementBookmakerOut"
      },
      "SteamMoveOut": {
        "properties": {
          "market": {
            "type": "string",
            "title": "Market"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "books_quoting": {
            "type": "integer",
            "title": "Books Quoting"
          },
          "books_moved": {
            "type": "integer",
            "title": "Books Moved"
          },
          "consensus_direction": {
            "type": "string",
            "title": "Consensus Direction"
          },
          "avg_prob_shift": {
            "type": "number",
            "title": "Avg Prob Shift"
          },
          "consensus_point_shift": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consensus Point Shift"
          },
          "steam_score": {
            "type": "number",
            "title": "Steam Score"
          }
        },
        "type": "object",
        "required": [
          "market",
          "name",
          "books_quoting",
          "books_moved",
          "consensus_direction",
          "avg_prob_shift",
          "steam_score"
        ],
        "title": "SteamMoveOut"
      },
      "EventMovementOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "bookmakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MovementBookmakerOut"
            },
            "title": "Bookmakers"
          },
          "steam": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SteamMoveOut"
            },
            "title": "Steam"
          },
          "redacted": {
            "type": "boolean",
            "default": false,
            "title": "Redacted"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "bookmakers",
          "steam"
        ],
        "title": "EventMovementOut"
      },
      "WeatherOut": {
        "properties": {
          "temperature_f": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Temperature F"
          },
          "humidity_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Humidity Pct"
          },
          "precip_probability_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Precip Probability Pct"
          },
          "precip_in": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Precip In"
          },
          "wind_speed_mph": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wind Speed Mph"
          },
          "wind_gust_mph": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wind Gust Mph"
          },
          "wind_direction_deg": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wind Direction Deg"
          },
          "wind_direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wind Direction"
          },
          "conditions": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conditions"
          },
          "observed_for": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Observed For"
          }
        },
        "type": "object",
        "title": "WeatherOut"
      },
      "GameContextOut": {
        "properties": {
          "event_id": {
            "type": "string",
            "title": "Event Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Venue"
          },
          "roof_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Roof Type"
          },
          "is_indoor": {
            "type": "boolean",
            "default": false,
            "title": "Is Indoor"
          },
          "home_probable_pitcher": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Probable Pitcher"
          },
          "away_probable_pitcher": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Away Probable Pitcher"
          },
          "home_probable_pitcher_hand": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Probable Pitcher Hand",
            "description": "Throwing hand of the probable starter: L, R, or S (switch)."
          },
          "away_probable_pitcher_hand": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Away Probable Pitcher Hand",
            "description": "Throwing hand of the probable starter: L, R, or S (switch)."
          },
          "lineup_confirmed": {
            "type": "boolean",
            "default": false,
            "title": "Lineup Confirmed"
          },
          "home_plate_umpire": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Plate Umpire"
          },
          "weather": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WeatherOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "event_id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time"
        ],
        "title": "GameContextOut"
      },
      "EventStatsOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "home_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Score"
          },
          "away_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Away Score"
          },
          "stats": {
            "items": {
              "$ref": "#/components/schemas/PlayerStatOut"
            },
            "type": "array",
            "title": "Stats"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "status",
          "home_score",
          "away_score",
          "stats"
        ],
        "title": "EventStatsOut"
      },
      "FuturesEventOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/FuturesMarketOut"
            },
            "type": "array",
            "title": "Markets"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "title",
          "commence_time",
          "markets"
        ],
        "title": "FuturesEventOut"
      },
      "FuturesMarketOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "bookmaker": {
            "type": "string",
            "title": "Bookmaker"
          },
          "bookmaker_title": {
            "type": "string",
            "title": "Bookmaker Title"
          },
          "last_update": {
            "type": "string",
            "format": "date-time",
            "title": "Last Update"
          },
          "book_updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Updated At"
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/FuturesOutcomeOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "description",
          "bookmaker",
          "bookmaker_title",
          "last_update",
          "outcomes"
        ],
        "title": "FuturesMarketOut"
      },
      "FuturesOutcomeOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price"
          },
          "price_decimal": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Decimal"
          }
        },
        "type": "object",
        "required": [
          "name",
          "price",
          "price_decimal"
        ],
        "title": "FuturesOutcomeOut"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "MarketHistoryOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Game-period bucket. Null for full-game markets."
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/OutcomeHistoryOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "description",
          "outcomes"
        ],
        "title": "MarketHistoryOut"
      },
      "MarketOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "last_update": {
            "type": "string",
            "format": "date-time",
            "title": "Last Update"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Game-period bucket (q1..q4, h1/h2, p1..p3, i1..i9, f3/f5/f7). Null for full-game markets."
          },
          "suspended_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "Set when this book has taken the market off the board pregame (the pull-side twin of the market_suspended webhook). Null = on the board. The outcomes are then the last quoted legs, not a live price. Clears the moment the book delivers the market again."
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/OutcomeOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "last_update",
          "outcomes"
        ],
        "title": "MarketOut"
      },
      "OddsSnapshotOut": {
        "properties": {
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "title": "Recorded At"
          },
          "book_updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Updated At"
          },
          "book_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Version"
          }
        },
        "type": "object",
        "required": [
          "price",
          "point",
          "recorded_at"
        ],
        "title": "OddsSnapshotOut"
      },
      "OutcomeHistoryOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "snapshots": {
            "items": {
              "$ref": "#/components/schemas/OddsSnapshotOut"
            },
            "type": "array",
            "title": "Snapshots"
          },
          "snapshots_available": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Snapshots Available"
          },
          "redacted": {
            "type": "boolean",
            "title": "Redacted",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "name",
          "description",
          "snapshots"
        ],
        "title": "OutcomeHistoryOut"
      },
      "OutcomeOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "book_updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Updated At"
          },
          "book_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Book Version"
          },
          "payout_multiplier": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Payout Multiplier",
            "description": "DFS payout multiplier for boosted/discounted picks (Underdog Fantasy). Populated on EVERY Underdog outcome; null means the book is not Underdog. 1.0 = standard pick whose quoted price carries the full payout; a value such as 0.75 (discount) or 1.5 (boost) scales the effective payout. Keep only payout_multiplier == 1.0 when comparing DFS lines to sportsbook consensus \u2014 filtering on non-null would drop every Underdog line."
          },
          "dfs_odds_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "DFS Odds Type",
            "description": "PrizePicks projection flavor: 'standard' (the true market line), 'goblin' (easier line / lower payout) or 'demon' (harder line / higher payout). Null for every traditional sportsbook. Filter to 'standard' to get PrizePicks's market line; goblin/demon are boosted/discounted alternates that each appear as their own per-line market. PrizePicks publishes no numeric multiplier for these, so only the flavor is surfaced."
          },
          "last_change_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Change At",
            "description": "PropLine's observed timestamp of the last time this outcome's price actually changed. Distinct from book_updated_at (the book's own publish-time, which only Bovada exposes): last_change_at is derived by PropLine and is populated for EVERY book, including Pinnacle and PrizePicks. We only advance it when price_american moves, so it is a true 'this line last changed at T' signal \u2014 compare it across books in one /odds call to detect repricing lag without a separate /odds/history call."
          },
          "line_gap": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Line Gap",
            "description": "Signed line-difficulty delta for a PrizePicks goblin/demon outcome: point - the standard line for the same player+stat. Positive on a harder (demon) line, negative on an easier (goblin) line. Null when the outcome is not a PrizePicks goblin/demon, or when no standard line exists for that player+stat (PrizePicks often posts a player goblin/demon-only). PrizePicks publishes no numeric per-pick payout multiplier, so the flavor + this line gap are the modelable signals for fitting per-pick payout adjustments."
          },
          "book_outcome_id": {
            "type": "string",
            "nullable": true,
            "description": "This book's own identifier for the priced selection / contract (Kalshi: the per-contract market ticker). Only set when the request passed includeBookIds=true. A two-sided market can share one id across both legs \u2014 the id is the contract, `name` is the side."
          },
          "liquidity": {
            "type": "number",
            "nullable": true,
            "description": "Dollars a bettor can actually stake at the quoted price. Exchange books publishing resting size only (ProphetX today); null for every other book, and for an exchange quote whose size the feed omitted. On a P2P exchange the best price is often a thin offer with only a few dollars behind it \u2014 filter or discount small values before treating the price as bettable. Refreshed every poll cycle independently of price movement; liquidity changes never appear in /odds/history or fire line_movement webhooks."
          }
        },
        "type": "object",
        "required": [
          "name",
          "description",
          "price",
          "point"
        ],
        "title": "OutcomeOut"
      },
      "PlayerHistoryEntryOut": {
        "properties": {
          "event_id": {
            "type": "string",
            "title": "Event Id"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "bookmaker": {
            "type": "string",
            "title": "Bookmaker"
          },
          "bookmaker_title": {
            "type": "string",
            "title": "Bookmaker Title"
          },
          "line": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Line"
          },
          "over_price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Over Price"
          },
          "under_price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Under Price"
          },
          "actual_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actual Value"
          },
          "over_result": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Over Result"
          },
          "under_result": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Under Result"
          },
          "resolved_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolved At"
          },
          "redacted": {
            "type": "boolean",
            "title": "Redacted",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "event_id",
          "commence_time",
          "home_team",
          "away_team",
          "bookmaker",
          "bookmaker_title",
          "line",
          "over_price",
          "under_price",
          "actual_value",
          "over_result",
          "under_result",
          "resolved_at"
        ],
        "title": "PlayerHistoryEntryOut"
      },
      "PlayerHistoryOut": {
        "properties": {
          "player_name": {
            "type": "string",
            "title": "Player Name"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "market": {
            "type": "string",
            "title": "Market"
          },
          "entries": {
            "items": {
              "$ref": "#/components/schemas/PlayerHistoryEntryOut"
            },
            "type": "array",
            "title": "Entries"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "player_name",
          "sport_key",
          "market",
          "entries"
        ],
        "title": "PlayerHistoryOut"
      },
      "HitRateSplitOut": {
        "properties": {
          "window": {
            "type": "integer",
            "title": "Window"
          },
          "games": {
            "type": "integer",
            "title": "Games"
          },
          "over": {
            "type": "integer",
            "title": "Over"
          },
          "under": {
            "type": "integer",
            "title": "Under"
          },
          "push": {
            "type": "integer",
            "title": "Push"
          },
          "over_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Over Pct"
          }
        },
        "type": "object",
        "required": [
          "window",
          "games",
          "over",
          "under",
          "push",
          "over_pct"
        ],
        "title": "HitRateSplitOut"
      },
      "TrendStreakOut": {
        "properties": {
          "result": {
            "type": "string",
            "title": "Result"
          },
          "length": {
            "type": "integer",
            "title": "Length"
          }
        },
        "type": "object",
        "required": [
          "result",
          "length"
        ],
        "title": "TrendStreakOut"
      },
      "TrendLastGameOut": {
        "properties": {
          "event_id": {
            "type": "string",
            "title": "Event Id"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "line": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Line"
          },
          "actual_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actual Value"
          },
          "result": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Result"
          }
        },
        "type": "object",
        "required": [
          "event_id",
          "commence_time",
          "line",
          "actual_value",
          "result"
        ],
        "title": "TrendLastGameOut"
      },
      "PlayerMarketTrendOut": {
        "properties": {
          "market": {
            "type": "string",
            "title": "Market"
          },
          "games_graded": {
            "type": "integer",
            "title": "Games Graded"
          },
          "reference_bookmaker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reference Bookmaker"
          },
          "reference_bookmaker_title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reference Bookmaker Title"
          },
          "recent_line": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recent Line"
          },
          "avg_actual": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Avg Actual"
          },
          "last_5": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HitRateSplitOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_10": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HitRateSplitOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_20": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HitRateSplitOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_50": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HitRateSplitOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "current_streak": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TrendStreakOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_game": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TrendLastGameOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "redacted": {
            "type": "boolean",
            "default": false,
            "title": "Redacted"
          }
        },
        "type": "object",
        "required": [
          "market",
          "games_graded"
        ],
        "title": "PlayerMarketTrendOut"
      },
      "PlayerTrendsOut": {
        "properties": {
          "player_name": {
            "type": "string",
            "title": "Player Name"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "dfs_odds_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "DFS Odds Type",
            "description": "Echo of the dfs_odds_type filter that scoped these trends (PrizePicks flavor: standard/goblin/demon). Null = cross-book, flavor-agnostic."
          },
          "markets": {
            "items": {
              "$ref": "#/components/schemas/PlayerMarketTrendOut"
            },
            "type": "array",
            "title": "Markets"
          },
          "upgrade_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upgrade Url"
          }
        },
        "type": "object",
        "required": [
          "player_name",
          "sport_key",
          "markets"
        ],
        "title": "PlayerTrendsOut"
      },
      "PlayerStatOut": {
        "properties": {
          "player_name": {
            "type": "string",
            "title": "Player Name"
          },
          "team_abbr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Team Abbr"
          },
          "stat_type": {
            "type": "string",
            "title": "Stat Type"
          },
          "stat_value": {
            "type": "number",
            "title": "Stat Value"
          }
        },
        "type": "object",
        "required": [
          "player_name",
          "team_abbr",
          "stat_type",
          "stat_value"
        ],
        "title": "PlayerStatOut"
      },
      "ResolvedMarketOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "outcomes": {
            "items": {
              "$ref": "#/components/schemas/ResolvedOutcomeOut"
            },
            "type": "array",
            "title": "Outcomes"
          }
        },
        "type": "object",
        "required": [
          "key",
          "description",
          "outcomes"
        ],
        "title": "ResolvedMarketOut"
      },
      "ResolvedOutcomeOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "price": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price"
          },
          "point": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Point"
          },
          "resolution": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolution"
          },
          "actual_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actual Value"
          },
          "resolved_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolved At"
          },
          "redacted": {
            "type": "boolean",
            "title": "Redacted",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "name",
          "description",
          "price",
          "point",
          "resolution",
          "actual_value",
          "resolved_at"
        ],
        "title": "ResolvedOutcomeOut"
      },
      "ScoreOut": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "home_team": {
            "type": "string",
            "title": "Home Team"
          },
          "away_team": {
            "type": "string",
            "title": "Away Team"
          },
          "commence_time": {
            "type": "string",
            "format": "date-time",
            "title": "Commence Time"
          },
          "live": {
            "type": "boolean",
            "title": "Live",
            "default": false
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "home_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Score"
          },
          "away_score": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Away Score"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sport_key",
          "home_team",
          "away_team",
          "commence_time",
          "status",
          "home_score",
          "away_score"
        ],
        "title": "ScoreOut"
      },
      "GrandSalamiBookOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "games_priced": {
            "type": "integer",
            "title": "Games Priced"
          },
          "line": {
            "type": "number",
            "title": "Line"
          },
          "result": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Result"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "games_priced",
          "line"
        ],
        "title": "GrandSalamiBookOut"
      },
      "GrandSalamiOut": {
        "properties": {
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "date": {
            "type": "string",
            "title": "Date"
          },
          "games_total": {
            "type": "integer",
            "title": "Games Total"
          },
          "games_completed": {
            "type": "integer",
            "title": "Games Completed"
          },
          "games_in_progress": {
            "type": "integer",
            "title": "Games In Progress"
          },
          "games_upcoming": {
            "type": "integer",
            "title": "Games Upcoming"
          },
          "actual_total_runs": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actual Total Runs"
          },
          "bookmakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GrandSalamiBookOut"
            },
            "title": "Bookmakers"
          }
        },
        "type": "object",
        "required": [
          "sport_key",
          "date",
          "games_total",
          "games_completed",
          "games_in_progress",
          "games_upcoming",
          "actual_total_runs",
          "bookmakers"
        ],
        "title": "GrandSalamiOut"
      },
      "DailyGoalsTotalBookOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "games_priced": {
            "type": "integer",
            "title": "Games Priced"
          },
          "line": {
            "type": "number",
            "title": "Line"
          },
          "result": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Result"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "games_priced",
          "line"
        ],
        "title": "DailyGoalsTotalBookOut"
      },
      "DailyGoalsTotalOut": {
        "properties": {
          "sport_key": {
            "type": "string",
            "title": "Sport Key"
          },
          "date": {
            "type": "string",
            "title": "Date"
          },
          "games_total": {
            "type": "integer",
            "title": "Games Total"
          },
          "games_completed": {
            "type": "integer",
            "title": "Games Completed"
          },
          "games_in_progress": {
            "type": "integer",
            "title": "Games In Progress"
          },
          "games_upcoming": {
            "type": "integer",
            "title": "Games Upcoming"
          },
          "actual_total_goals": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actual Total Goals"
          },
          "bookmakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyGoalsTotalBookOut"
            },
            "title": "Bookmakers"
          }
        },
        "type": "object",
        "required": [
          "sport_key",
          "date",
          "games_total",
          "games_completed",
          "games_in_progress",
          "games_upcoming",
          "actual_total_goals",
          "bookmakers"
        ],
        "title": "DailyGoalsTotalOut"
      },
      "SportOut": {
        "properties": {
          "key": {
            "type": "string",
            "title": "Key"
          },
          "title": {
            "type": "string",
            "title": "Title"
          },
          "active": {
            "type": "boolean",
            "title": "Active"
          }
        },
        "type": "object",
        "required": [
          "key",
          "title",
          "active"
        ],
        "title": "SportOut"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "APIKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "APIKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "apiKey"
      }
    }
  },
  "servers": [
    {
      "url": "https://api.prop-line.com",
      "description": "PropLine production"
    }
  ],
  "security": [
    {
      "APIKeyHeader": []
    },
    {
      "APIKeyQuery": []
    }
  ]
}
