{
  "openapi": "3.0.1",
  "info": {
    "title": "SportWizzard API",
    "version": "1.0.0",
    "description": "The sports betting data API. Real-time odds from 35+ sportsbooks and DFS platforms, plus the underlying data to build your own models: players, teams, box-score stats, historical prices, and game context (weather, lineups, probable pitchers, venue, scores) in one canonical schema — and the full live snapshot. Edges and cross-book arbitrage are included as derived-signal conveniences. All responses use a consistent envelope ({success, data, nextCursor, meta}). Authenticate with the X-Api-Key header using a Clerk-issued API key. Pagination uses opaque cursors (pass meta/nextCursor back as ?cursor=). Reference endpoints (leagues, sportsbooks, teams, players, markets) are free and uncounted. Authenticated responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (epoch seconds) headers.",
    "contact": {
      "name": "SportWizzard",
      "url": "https://sportwizzard.com/developers",
      "email": "support@sportwizzard.com"
    },
    "termsOfService": "https://sportwizzard.com/terms"
  },
  "servers": [
    {
      "url": "https://api.sportwizzard.com"
    }
  ],
  "tags": [
    {
      "name": "Odds",
      "description": "Normalized odds across all books. Flat array, one row per book×market×selection."
    },
    {
      "name": "Stats & Historical",
      "description": "Player/team box stats and historical odds/arbitrage."
    },
    {
      "name": "Data",
      "description": "Model-builder data: event box scores, the live snapshot, bulk player stats, and account usage."
    },
    {
      "name": "Reference",
      "description": "Sportsbooks, leagues, markets, teams and players. Free and long-cacheable."
    },
    {
      "name": "Derived",
      "description": "Edges (DFS value vs sharp books) and arbitrage — the SportWizzard moat."
    },
    {
      "name": "Events",
      "description": "Events/fixtures — the spine of the API. Filter by league, team, status, time."
    }
  ],
  "paths": {
    "/api/v1/teams": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List teams",
        "description": "Teams, optionally filtered by league. Keyset-paginated over the team id.",
        "operationId": "teams",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code filter, e.g. mlb",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max teams per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseTeamDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/teams/{teamId}/odds": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "Odds for one team",
        "description": "All prices across books for markets where this team id is the home or away team. Keyset-paginated (limit + cursor) exactly like /odds.",
        "operationId": "teamOdds",
        "parameters": [
          {
            "name": "teamId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
            },
            "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
          },
          {
            "name": "odds_format",
            "in": "query",
            "description": "Price representation: american, decimal, probability, or all (default all = both priceAmerican and priceDecimal, unchanged). american or decimal returns only that price field; probability replaces the price fields with priceProbability (implied probability = 1/decimal, 4 decimal places). Invalid values return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "american",
                "decimal",
                "probability",
                "all"
              ],
              "default": "all",
              "example": "probability"
            },
            "example": "probability"
          },
          {
            "name": "is_main",
            "in": "query",
            "description": "When true, keep only each market's PRIMARY line per book: among a book's alternate over/under lines for the same market + period + player/team scope, the line whose two opposing implied probabilities are most balanced. Single-line and non-over/under markets pass through unchanged.",
            "required": false,
            "schema": {
              "type": "boolean",
              "example": true
            },
            "example": true
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max markets per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/teams/{id}": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Get a team",
        "description": "A single team by id.",
        "operationId": "team",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
            },
            "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseTeamDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/teams/{id}/stats": {
      "get": {
        "tags": [
          "Stats & Historical"
        ],
        "summary": "Team box stats",
        "description": "Per-event team box stats, optionally filtered to a season (year). The stats field is the raw per-event team stat JSON.",
        "operationId": "teamStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
            },
            "example": "7d0a7ec8-138a-11f1-aba1-de512ebea802"
          },
          {
            "name": "season",
            "in": "query",
            "description": "Season year filter, e.g. 2025",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 2025
            },
            "example": 2025
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseTeamStatRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/status": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Platform status",
        "description": "Live market and sportsbook counts.",
        "operationId": "status",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseStatus"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stats/players": {
      "get": {
        "tags": [
          "Data"
        ],
        "summary": "Bulk player box stats",
        "description": "Per-event player box stats filtered by event_id, team_id, and/or player_id (at least one required). Reads by indexed key and keyset-paginates over (eventId, playerId). Lets model builders pull stats in bulk without walking events one-by-one.",
        "operationId": "statsPlayers",
        "parameters": [
          {
            "name": "event_id",
            "in": "query",
            "description": "Event id filter",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "team_id",
            "in": "query",
            "description": "Team id filter",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "player_id",
            "in": "query",
            "description": "Player id filter",
            "required": false,
            "schema": {
              "type": "string",
              "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
            },
            "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max rows per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponsePlayerStatRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sportsbooks": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List sportsbooks",
        "description": "All sources currently ingesting, with live market counts. Recommended poll interval: 5 min.",
        "operationId": "sportsbooks",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseSportsbook"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/snapshot": {
      "get": {
        "tags": [
          "Data"
        ],
        "summary": "Live snapshot",
        "description": "The full live board of all event markets, served straight from the pre-built gzip blob (~5ms). Response is Content-Encoding: gzip — decompress client-side. Send If-None-Match with the prior ETag to get a 304 when the snapshot hasn't changed.",
        "operationId": "snapshot",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/players": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List players",
        "description": "Players, optionally filtered by league and/or team. Keyset-paginated over the player id.",
        "operationId": "players",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code filter, e.g. mlb",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "team",
            "in": "query",
            "description": "Team id filter (alias of team_id). If both team and team_id are given, team_id wins.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "team_id",
            "in": "query",
            "description": "Team id filter (alias of team). If both are given, team_id wins.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max players per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponsePlayerDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/players/{playerId}/odds": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "Odds for one player",
        "description": "All prop prices across books for a player — markets whose outcomes reference this resolved player id. Keyset-paginated (limit + cursor) exactly like /odds.",
        "operationId": "playerOdds",
        "parameters": [
          {
            "name": "playerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
            },
            "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
          },
          {
            "name": "odds_format",
            "in": "query",
            "description": "Price representation: american, decimal, probability, or all (default all = both priceAmerican and priceDecimal, unchanged). american or decimal returns only that price field; probability replaces the price fields with priceProbability (implied probability = 1/decimal, 4 decimal places). Invalid values return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "american",
                "decimal",
                "probability",
                "all"
              ],
              "default": "all",
              "example": "probability"
            },
            "example": "probability"
          },
          {
            "name": "is_main",
            "in": "query",
            "description": "When true, keep only each market's PRIMARY line per book: among a book's alternate over/under lines for the same market + period + player/team scope, the line whose two opposing implied probabilities are most balanced. Single-line and non-over/under markets pass through unchanged.",
            "required": false,
            "schema": {
              "type": "boolean",
              "example": true
            },
            "example": true
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max markets per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/players/{id}": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Get a player",
        "description": "A single player by id.",
        "operationId": "player",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
            },
            "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponsePlayerDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/players/{id}/stats": {
      "get": {
        "tags": [
          "Stats & Historical"
        ],
        "summary": "Player box stats",
        "description": "Per-event box stats for a player, optionally filtered to a season (year). The data field is the raw per-event stat JSON.",
        "operationId": "playerStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
            },
            "example": "7ebca2e5-138a-11f1-aba1-de512ebea802"
          },
          {
            "name": "season",
            "in": "query",
            "description": "Season year filter, e.g. 2025",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 2025
            },
            "example": 2025
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponsePlayerStatRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/odds": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "List odds",
        "description": "Normalized odds across books, filterable and keyset-paginated. Scope with any of event_id / player_id / team_id / sportsbook / market / league (all optional; unscoped is allowed but paginates hard). Recommended poll interval: 5-15s. ETag/If-None-Match supported.",
        "operationId": "odds",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code(s). Comma-separated for ANY-of matching (up to 20 values; case-insensitive exact per token), e.g. mlb or mlb,nba. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "sportsbook",
            "in": "query",
            "description": "Sportsbook/source id(s). Comma-separated for ANY-of matching (up to 20 values; case-insensitive exact per token), e.g. draftkings,fanduel. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "draftkings,fanduel"
            },
            "example": "draftkings,fanduel"
          },
          {
            "name": "market",
            "in": "query",
            "description": "Market type filter(s); each token is a substring match. Comma-separated for ANY-of matching (up to 20 values), e.g. MONEYLINE or MONEYLINE,PLAYER_TOTAL. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_id",
            "in": "query",
            "description": "Filter to a single event id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "player_id",
            "in": "query",
            "description": "Filter to markets referencing this resolved player id (props)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "team_id",
            "in": "query",
            "description": "Filter to markets where this team id is home or away",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "odds_format",
            "in": "query",
            "description": "Price representation: american, decimal, probability, or all (default all = both priceAmerican and priceDecimal, unchanged). american or decimal returns only that price field; probability replaces the price fields with priceProbability (implied probability = 1/decimal, 4 decimal places). Invalid values return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "american",
                "decimal",
                "probability",
                "all"
              ],
              "default": "all",
              "example": "probability"
            },
            "example": "probability"
          },
          {
            "name": "is_main",
            "in": "query",
            "description": "When true, keep only each market's PRIMARY line per book: among a book's alternate over/under lines for the same market + period + player/team scope, the line whose two opposing implied probabilities are most balanced. Single-line and non-over/under markets pass through unchanged.",
            "required": false,
            "schema": {
              "type": "boolean",
              "example": true
            },
            "example": true
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max markets per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/odds/updated": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "Odds delta feed",
        "description": "Markets whose lastSeenEpoch >= 'since' (an ISO-8601 instant or epoch millis). Keyset-paginated over the same per-source order as /odds. Poll this to sync only what changed. Scopeable with league / sportsbook / market (same comma-separated ANY-of semantics as /odds) and odds_format.",
        "operationId": "oddsUpdated",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "description": "ISO-8601 instant (2026-07-09T00:00:00Z) or epoch millis",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2025-07-01T00:00:00Z"
            },
            "example": "2025-07-01T00:00:00Z"
          },
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code(s). Comma-separated for ANY-of matching (up to 20 values; case-insensitive exact per token), e.g. mlb or mlb,nba. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "sportsbook",
            "in": "query",
            "description": "Sportsbook/source id(s). Comma-separated for ANY-of matching (up to 20 values; case-insensitive exact per token), e.g. draftkings,fanduel. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "draftkings,fanduel"
            },
            "example": "draftkings,fanduel"
          },
          {
            "name": "market",
            "in": "query",
            "description": "Market type filter(s); each token is a substring match. Comma-separated for ANY-of matching (up to 20 values), e.g. MONEYLINE or MONEYLINE,PLAYER_TOTAL. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "odds_format",
            "in": "query",
            "description": "Price representation: american, decimal, probability, or all (default all = both priceAmerican and priceDecimal, unchanged). american or decimal returns only that price field; probability replaces the price fields with priceProbability (implied probability = 1/decimal, 4 decimal places). Invalid values return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "american",
                "decimal",
                "probability",
                "all"
              ],
              "default": "all",
              "example": "probability"
            },
            "example": "probability"
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max markets per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/markets": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Market catalog",
        "description": "Distinct market types we currently carry (aggregated across subtypes), with live counts. Recommended poll interval: 5 min.",
        "operationId": "markets",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseMarketType"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/markets/active": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Active market catalog",
        "description": "Distinct (marketType, marketSubtype) pairs currently live in the cache, with counts. Recommended poll interval: 1 min.",
        "operationId": "marketsActive",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseMarketType"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leagues": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List active leagues",
        "description": "Leagues with an in-progress season. Recommended poll interval: 1 hour.",
        "operationId": "leagues",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseString"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/seasons": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List seasons",
        "description": "Seasons for a given year across all leagues. Recommended poll interval: 1 hour.",
        "operationId": "seasons",
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "description": "Calendar year of the season, e.g. 2025",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 2026
            },
            "example": 2026
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseSeasonDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/historical/odds": {
      "get": {
        "tags": [
          "Stats & Historical"
        ],
        "summary": "Historical odds",
        "description": "Reconstructs each selection's American price at (or just before) a given time from its priceHistory. Requires event_id. If date is omitted, returns the current price. Player attribution is omitted for historical rows.",
        "operationId": "historicalOdds",
        "parameters": [
          {
            "name": "event_id",
            "in": "query",
            "description": "Event id (required)",
            "required": true,
            "schema": {
              "type": "string",
              "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
            },
            "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
          },
          {
            "name": "date",
            "in": "query",
            "description": "As-of time (ISO-8601). Default: latest known price.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseHistoricalOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/historical/arbitrage": {
      "get": {
        "tags": [
          "Stats & Historical"
        ],
        "summary": "Historical arbitrage",
        "description": "Arbitrage that existed at a point in time, replayed from priceHistory. The underlying store is point-in-time, so a from/to window is evaluated at 'to' with a staleness window of (to−from); pass a single 'to' for a snapshot. Reuses the live historical-arbitrage engine.",
        "operationId": "historicalArbitrage",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "description": "Window start (ISO-8601). Optional; sets the staleness window with 'to'.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2025-07-01T00:00:00Z"
            },
            "example": "2025-07-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "description": "As-of / window end (ISO-8601). Defaults to 'from' if omitted.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2025-07-10T00:00:00Z"
            },
            "example": "2025-07-10T00:00:00Z"
          },
          {
            "name": "min_profit",
            "in": "query",
            "description": "Minimum profit margin (fractional). Default 0.001.",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max results (default 500)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseArbRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "List events",
        "description": "Events/fixtures filtered by league, team_id, status, and a start-time window (starts_after/starts_before, ISO-8601; default: now to now+14d). Keyset-paginated over (startTime, id).",
        "operationId": "events",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code, e.g. mlb",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "team_id",
            "in": "query",
            "description": "Filter to events involving this team id (home or away)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Event status, e.g. scheduled, in_progress, final",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "starts_after",
            "in": "query",
            "description": "Lower bound on start time (ISO-8601). Default now.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "starts_before",
            "in": "query",
            "description": "Upper bound on start time (ISO-8601). Default now+14d.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max events per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseEventDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/{id}": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "Get an event",
        "description": "A single event by id, enriched for model builders: team names, status, league, hasOdds, venueId, seasonYear, the raw matchup-context JSON (weather/lineups/probable pitchers/officials, league-specific), and final scores when the box score is available. The list endpoints stay lean.",
        "operationId": "event",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
            },
            "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseEventDetailDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/{id}/stats": {
      "get": {
        "tags": [
          "Data"
        ],
        "summary": "Event box score",
        "description": "The complete box score for one event — team-level rows (scores/result + raw team stat JSON) and per-player rows (raw per-event stat JSON). Bounded by the event's rosters, so it is returned in full (unpaginated). Model-builder gold.",
        "operationId": "eventStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
            },
            "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseEventStatsDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/{eventId}/odds": {
      "get": {
        "tags": [
          "Odds"
        ],
        "summary": "Odds for one event",
        "description": "All book prices for a single event.",
        "operationId": "eventOdds",
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
            },
            "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
          },
          {
            "name": "odds_format",
            "in": "query",
            "description": "Price representation: american, decimal, probability, or all (default all = both priceAmerican and priceDecimal, unchanged). american or decimal returns only that price field; probability replaces the price fields with priceProbability (implied probability = 1/decimal, 4 decimal places). Invalid values return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "american",
                "decimal",
                "probability",
                "all"
              ],
              "default": "all",
              "example": "probability"
            },
            "example": "probability"
          },
          {
            "name": "is_main",
            "in": "query",
            "description": "When true, keep only each market's PRIMARY line per book: among a book's alternate over/under lines for the same market + period + player/team scope, the line whose two opposing implied probabilities are most balanced. Single-line and non-over/under markets pass through unchanged.",
            "required": false,
            "schema": {
              "type": "boolean",
              "example": true
            },
            "example": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseOddsRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/active": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "List active events",
        "description": "Only events that currently have live markets in the cache — the recommended entrypoint. Keyset-paginated over (startTime, id).",
        "operationId": "eventsActive",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code filter",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max events per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseEventDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/edges": {
      "get": {
        "tags": [
          "Derived"
        ],
        "summary": "List edges",
        "description": "DFS value plays vs sharp-book fair value, filterable by league, source, min_edge and event_id. Wraps the live edge engine. Recommended poll interval: 15-30s.",
        "operationId": "edges",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code filter, e.g. nba",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "source",
            "in": "query",
            "description": "DFS source filter, e.g. prizepicks, underdog",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_edge",
            "in": "query",
            "description": "Minimum edge (fractional, must be within [0, 1] — e.g. 0.02 = 2%). Default 0.02. Values outside [0, 1] return 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "event_id",
            "in": "query",
            "description": "Filter to a single event id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max edges per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseEdgeRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/arbitrage": {
      "get": {
        "tags": [
          "Derived"
        ],
        "summary": "List arbitrage",
        "description": "Risk-free arbitrage opportunities across books. type=two_way|three_way; min_profit is the fractional margin (0.001 = 0.1%). Wraps the live arbitrage engine (middles excluded). Recommended poll interval: 10-20s.",
        "operationId": "arbitrage",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Arb type: two_way or three_way (default: all non-middle)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "description": "League/competition code(s). Comma-separated for ANY-of matching (up to 20 values; case-insensitive exact per token), e.g. mlb or mlb,nba. More than 20 values returns 400 invalid_parameter.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "mlb"
            },
            "example": "mlb"
          },
          {
            "name": "event_id",
            "in": "query",
            "description": "Filter to a single event id",
            "required": false,
            "schema": {
              "type": "string",
              "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
            },
            "example": "03d8ece0-a31b-4754-a86a-e4f883288b7c"
          },
          {
            "name": "min_profit",
            "in": "query",
            "description": "Minimum profit margin (fractional, e.g. 0.001 = 0.1%). Default 0.001.",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a prior response",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max arbs per page (default 100, max 1000)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": 10
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseArbRow"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/account/usage": {
      "get": {
        "tags": [
          "Data"
        ],
        "summary": "Account usage",
        "description": "Plan tier, monthly usage/cap, and per-minute rate limit for the calling API key (Authorization: Bearer <api_key>). Unauthenticated callers get the effective anonymous plan (currently ENTERPRISE/unmetered, pre-billing) with monthlyUsed=null. Never errors.",
        "operationId": "accountUsage",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponseUsageDto"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ApiResponseTeamDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Meta": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int32"
          },
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "TeamDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "abbreviation": {
            "type": "string"
          },
          "league": {
            "type": "string"
          }
        }
      },
      "ApiResponseOddsRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OddsRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "OddsRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "sportsbook": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "market": {
            "type": "string"
          },
          "marketSubtype": {
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "selection": {
            "type": "string"
          },
          "priceAmerican": {
            "type": "integer",
            "format": "int32"
          },
          "priceDecimal": {
            "type": "number"
          },
          "line": {
            "type": "number"
          },
          "side": {
            "type": "string"
          },
          "teamSide": {
            "type": "string"
          },
          "teamName": {
            "type": "string"
          },
          "playerId": {
            "type": "string"
          },
          "playerName": {
            "type": "string"
          },
          "dfsMultiplier": {
            "type": "number"
          },
          "suspended": {
            "type": "boolean"
          },
          "eventStartTime": {
            "type": "string"
          },
          "updated": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiResponseTeamStatRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamStatRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "JsonNode": {
        "type": "object"
      },
      "TeamStatRow": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "homeId": {
            "type": "string"
          },
          "awayId": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "homeScore": {
            "type": "integer",
            "format": "int32"
          },
          "awayScore": {
            "type": "integer",
            "format": "int32"
          },
          "result": {
            "type": "integer",
            "format": "int32"
          },
          "stats": {
            "$ref": "#/components/schemas/JsonNode"
          }
        }
      },
      "ApiResponseStatus": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Status"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "totalMarkets": {
            "type": "integer",
            "format": "int32"
          },
          "sportsbooks": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ApiResponsePlayerStatRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlayerStatRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "PlayerStatRow": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "playerId": {
            "type": "string"
          },
          "teamId": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "data": {
            "$ref": "#/components/schemas/JsonNode"
          }
        }
      },
      "ApiResponseSportsbook": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Sportsbook"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Sportsbook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "marketCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ApiResponsePlayerDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlayerDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "PlayerDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "teamId": {
            "type": "string"
          },
          "position": {
            "type": "string"
          }
        }
      },
      "ApiResponseMarketType": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketType"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "MarketType": {
        "type": "object",
        "properties": {
          "marketType": {
            "type": "string"
          },
          "marketSubtype": {
            "type": "string"
          },
          "liveCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ApiResponseSeasonDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeasonDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "SeasonDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "year": {
            "type": "integer",
            "format": "int32"
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": "string"
          }
        }
      },
      "ApiResponseString": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "ApiResponseHistoricalOddsRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoricalOddsRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "HistoricalOddsRow": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "sportsbook": {
            "type": "string"
          },
          "market": {
            "type": "string"
          },
          "marketSubtype": {
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "selection": {
            "type": "string"
          },
          "side": {
            "type": "string"
          },
          "line": {
            "type": "number",
            "format": "double"
          },
          "priceAmerican": {
            "type": "integer",
            "format": "int32"
          },
          "asOf": {
            "type": "string"
          }
        }
      },
      "ApiResponseArbRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArbRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "ArbRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "profitPercent": {
            "type": "number",
            "format": "double"
          },
          "league": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventHomeTeam": {
            "type": "string"
          },
          "eventAwayTeam": {
            "type": "string"
          },
          "eventStartTime": {
            "type": "string"
          },
          "playerId": {
            "type": "string"
          },
          "playerName": {
            "type": "string"
          },
          "lastSeen": {
            "type": "string"
          },
          "selections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArbitrageSelectionDetail"
            }
          }
        }
      },
      "ArbitrageSelectionDetail": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          },
          "liquidity": {
            "type": "string"
          },
          "liquidityAmount": {
            "type": "number",
            "format": "double"
          },
          "volumeTier": {
            "type": "string"
          },
          "volumeAmount": {
            "type": "number",
            "format": "double"
          },
          "marketType": {
            "type": "string"
          },
          "marketLabel": {
            "type": "string"
          },
          "marketSubtype": {
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "includesOvertime": {
            "type": "boolean"
          },
          "outcome": {
            "type": "string"
          },
          "outcomeCode": {
            "type": "string"
          },
          "lineValue": {
            "type": "number",
            "format": "double"
          },
          "targetValue": {
            "type": "number",
            "format": "double"
          },
          "teamSide": {
            "type": "string"
          },
          "selectionLabel": {
            "type": "string"
          },
          "playerId": {
            "type": "string",
            "format": "uuid"
          },
          "playerName": {
            "type": "string"
          },
          "odds": {
            "type": "integer",
            "format": "int32"
          },
          "stakeFraction": {
            "type": "number",
            "format": "double"
          },
          "sourceMarketId": {
            "type": "string"
          },
          "sourceSelectionId": {
            "type": "string"
          },
          "sourceEventId": {
            "type": "string"
          },
          "lastSeen": {
            "type": "string"
          },
          "eventMarketId": {
            "type": "string",
            "format": "uuid"
          },
          "selectionId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "ApiResponseEventDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "EventDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "homeTeamId": {
            "type": "string"
          },
          "homeTeamName": {
            "type": "string"
          },
          "awayTeamId": {
            "type": "string"
          },
          "awayTeamName": {
            "type": "string"
          },
          "startTime": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "hasOdds": {
            "type": "boolean"
          }
        }
      },
      "ApiResponseEventDetailDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventDetailDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "EventDetailDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "homeTeamId": {
            "type": "string"
          },
          "homeTeamName": {
            "type": "string"
          },
          "awayTeamId": {
            "type": "string"
          },
          "awayTeamName": {
            "type": "string"
          },
          "startTime": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "hasOdds": {
            "type": "boolean"
          },
          "venueId": {
            "type": "string"
          },
          "seasonYear": {
            "type": "integer",
            "format": "int32"
          },
          "context": {
            "$ref": "#/components/schemas/JsonNode"
          },
          "homeScore": {
            "type": "integer",
            "format": "int32"
          },
          "awayScore": {
            "type": "integer",
            "format": "int32"
          },
          "result": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ApiResponseEventStatsDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventStatsDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "EventStatsDto": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "teams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamStatRow"
            }
          },
          "players": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlayerStatRow"
            }
          }
        }
      },
      "ApiResponseEdgeRow": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeRow"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "BookOdds": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "over": {
            "type": "integer",
            "format": "int32"
          },
          "under": {
            "type": "integer",
            "format": "int32"
          },
          "impliedProb": {
            "type": "number",
            "format": "double"
          },
          "lastSeen": {
            "type": "string"
          }
        }
      },
      "EdgeRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventHomeTeam": {
            "type": "string"
          },
          "eventAwayTeam": {
            "type": "string"
          },
          "eventStartTime": {
            "type": "string"
          },
          "market": {
            "type": "string"
          },
          "statType": {
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "line": {
            "type": "number",
            "format": "double"
          },
          "side": {
            "type": "string"
          },
          "playerId": {
            "type": "string"
          },
          "playerName": {
            "type": "string"
          },
          "playerTeamName": {
            "type": "string"
          },
          "dfsSource": {
            "type": "string"
          },
          "dfsMultiplier": {
            "type": "number",
            "format": "double"
          },
          "dfsSelectionLabel": {
            "type": "string"
          },
          "bookSource": {
            "type": "string"
          },
          "bookImpliedProbability": {
            "type": "number",
            "format": "double"
          },
          "oddsByBook": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookOdds"
            }
          }
        }
      },
      "ApiResponseUsageDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageDto"
            }
          },
          "nextCursor": {
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "UsageDto": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string"
          },
          "monthlyUsed": {
            "type": "integer",
            "format": "int32"
          },
          "monthlyCap": {
            "type": "integer",
            "format": "int32"
          },
          "rateLimitPerMin": {
            "type": "integer",
            "format": "int32"
          },
          "authenticated": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          }
        }
      }
    }
  }
}
