{
  "openapi": "3.1.0",
  "info": {
    "title": "SharpAPI",
    "version": "2.0.0",
    "description": "Real-time sports betting odds API with +EV detection, arbitrage, middles, and low-hold opportunities.\n\n## Authentication\n\nAll authenticated endpoints accept an API key via one of three methods:\n\n| Method | Header / Param | Use case |\n|--------|---------------|----------|\n| `X-API-Key` | `X-API-Key: sk_live_...` | Recommended for server-side |\n| `Authorization` | `Authorization: Bearer sk_live_...` | Standard Bearer token |\n| `api_key` query | `?api_key=sk_live_...` | SSE/EventSource (cannot set headers) |\n\n## Subscription Tiers\n\n| Tier | Rate Limit | Data Delay | Max Books | EV | Arb | Middles | Game State |\n|------|-----------|------------|-----------|-----|-----|---------|------------|\n| Free | 12/min | 60s | 2 (DK, FD) | - | - | - | - |\n| Hobby | 120/min | Real-time | 5 | - | Yes | - | - |\n| Pro | 300/min | Real-time | 15 | Yes | Yes | Yes | - |\n| Sharp | 1000/min | Real-time | All | Yes | Yes | Yes | - |\n| Enterprise | Custom | Real-time | All | Yes | Yes | Yes | Yes |\n\n## Rate Limit Headers\n\nEvery authenticated response includes:\n\n- `X-RateLimit-Limit` - Requests allowed per minute\n- `X-RateLimit-Remaining` - Requests remaining in current window\n- `X-RateLimit-Reset` - Unix timestamp when the window resets\n- `X-Data-Delay` - Odds delay in seconds for your tier (0 = real-time)\n- `X-Request-Id` - Unique request identifier for support\n\n## WebSocket Streaming\n\nThe WebSocket endpoint at `wss://ws.sharpapi.io` is documented separately in [`asyncapi.yaml`](./asyncapi.yaml) (AsyncAPI 3.0). OpenAPI 3.x cannot express WebSocket subprotocols and message channels, so the SSE endpoint (`/stream`) is the only stream covered by this document.\n\n## MCP Server\n\nThe `POST /mcp` endpoint is a Model Context Protocol server (JSON-RPC 2.0 over Streamable HTTP). Tools are self-described at runtime via `tools/list`, so it's documented as a setup guide rather than an OpenAPI path — see [`/sdks/mcp`](https://docs.sharpapi.io/sdks/mcp).\n",
    "contact": {
      "name": "SharpAPI Support",
      "url": "https://sharpapi.io",
      "email": "support@sharpapi.io"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://sharpapi.io/terms"
    },
    "x-generated-at": "2026-05-02T11:19:40-04:00",
    "x-commit-sha": "5c41564"
  },
  "servers": [
    {
      "url": "https://api.sharpapi.io/api/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Service health and status"
    },
    {
      "name": "Reference Data",
      "description": "Sports, leagues, sportsbooks, markets, and teams"
    },
    {
      "name": "Events",
      "description": "Event discovery and details"
    },
    {
      "name": "Odds",
      "description": "Odds snapshots, comparisons, batch, and deltas"
    },
    {
      "name": "Opportunities",
      "description": "+EV, arbitrage, middles, and low-hold opportunities"
    },
    {
      "name": "Streaming",
      "description": "Real-time SSE streaming"
    },
    {
      "name": "Account",
      "description": "Account info, usage, and key management"
    },
    {
      "name": "Betting Splits",
      "description": "Public betting splits — handle % and bet % from DraftKings (recreational) and Circa Sports (sharp-friendly)."
    },
    {
      "name": "Deep Links",
      "description": "Sportsbook deep link generation"
    },
    {
      "name": "Futures",
      "description": "Futures markets and odds"
    },
    {
      "name": "Game State",
      "description": "Live game state data (Enterprise)"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Returns service health status, Redis connectivity, data freshness, and schema compatibility. No authentication required.",
        "tags": [
          "Health"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Service is healthy or degraded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "version",
                    "timestamp",
                    "checks"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degraded"
                      ]
                    },
                    "version": {
                      "type": "string",
                      "example": "v1"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "checks": {
                      "type": "object",
                      "properties": {
                        "redis": {
                          "$ref": "#/components/schemas/HealthCheck"
                        },
                        "data": {
                          "$ref": "#/components/schemas/HealthCheck"
                        },
                        "schema": {
                          "$ref": "#/components/schemas/HealthCheck"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "version": "v1",
                  "timestamp": "2026-03-09T14:00:00Z",
                  "checks": {
                    "redis": {
                      "status": "ok",
                      "latency_ms": 2
                    },
                    "data": {
                      "status": "ok",
                      "message": "28 sportsbook snapshots available"
                    },
                    "schema": {
                      "status": "ok",
                      "message": "All 14 required fields present"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service is down",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "down"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/splits": {
      "get": {
        "operationId": "listSplits",
        "summary": "List public betting splits",
        "description": "Returns the latest snapshot of public betting splits (handle % and bet %) for every tracked event. Data is sourced from DraftKings (recreational) and Circa Sports (sharp-friendly), refreshed every 5 minutes. Available on all tiers.",
        "tags": [
          "Betting Splits"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter to events that have splits for a market. Comma-separated.",
            "schema": {
              "type": "string",
              "enum": [
                "spread",
                "total",
                "moneyline"
              ]
            },
            "example": "spread,moneyline"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of splits, one entry per (event, sportsbook).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "pagination",
                    "updated_at"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SplitsGame"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/splits/history": {
      "get": {
        "operationId": "getSplitsHistory",
        "summary": "Splits history for one event",
        "description": "Returns the time series of splits snapshots for a single event from the Valkey sorted set `splits_history:{event_id}`. Snapshots are captured every ~5 minutes and retained for 48 hours. Available on all tiers.",
        "tags": [
          "Betting Splits"
        ],
        "parameters": [
          {
            "name": "event_id",
            "in": "query",
            "required": true,
            "description": "Canonical event ID (e.g. `mlb_guardians_orioles_2026-04-16`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "name": "start_time",
            "in": "query",
            "description": "Lower bound for snapshot timestamp. Accepts RFC 3339 (`2026-04-16T13:00:00Z`) or Unix seconds (`1776344602`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "end_time",
            "in": "query",
            "description": "Upper bound for snapshot timestamp. Same formats as `start_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum entries returned. 1-200, default 100. Ignored when a `sportsbook` filter is set (server returns all matching, then trims).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshots ordered oldest-first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SplitsHistoryEntry"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "event_id": {
                          "type": "string"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "books": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Distinct source sportsbooks present in this response."
                        },
                        "oldest": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "newest": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updated_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing required `event_id` query parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "event_id query parameter is required"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/sports": {
      "get": {
        "operationId": "listSports",
        "summary": "List sports",
        "description": "Returns available sports with event and live counts. Public endpoint with optional API key for higher rate limits.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "include_empty",
            "in": "query",
            "description": "Include sports with zero events",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of sports",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Sport"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "basketball",
                      "name": "Basketball",
                      "event_count": 42,
                      "live_count": 3,
                      "leagues": [
                        "nba",
                        "ncaab",
                        "wnba"
                      ]
                    },
                    {
                      "id": "football",
                      "name": "Football",
                      "event_count": 16,
                      "live_count": 0,
                      "leagues": [
                        "nfl",
                        "ncaaf"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/sports/{sportId}": {
      "get": {
        "operationId": "getSport",
        "summary": "Get sport by ID",
        "description": "Returns details for a single sport.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sportId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "basketball"
          }
        ],
        "responses": {
          "200": {
            "description": "Sport details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Sport"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/leagues": {
      "get": {
        "operationId": "listLeagues",
        "summary": "List leagues",
        "description": "Returns available leagues with event counts. Optionally filter by sport.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "query",
            "description": "Filter by sport ID",
            "schema": {
              "type": "string"
            },
            "example": "basketball"
          },
          {
            "name": "include_empty",
            "in": "query",
            "description": "Include leagues with zero events",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of leagues",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/League"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "nba",
                      "name": "NBA",
                      "sport": "basketball",
                      "event_count": 15,
                      "live_count": 2
                    },
                    {
                      "id": "ncaab",
                      "name": "NCAAB",
                      "sport": "basketball",
                      "event_count": 24,
                      "live_count": 1
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/sportsbooks": {
      "get": {
        "operationId": "listSportsbooks",
        "summary": "List sportsbooks",
        "description": "Returns available sportsbooks with status, capabilities, and event counts. Use `catalog=true` for a config-based catalog that doesn't require live data.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "region",
            "in": "query",
            "description": "Filter by region",
            "schema": {
              "type": "string",
              "enum": [
                "US",
                "UK",
                "EU",
                "AU",
                "GLOBAL"
              ]
            },
            "example": "US"
          },
          {
            "name": "sharp",
            "in": "query",
            "description": "Filter by sharp book status",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "catalog",
            "in": "query",
            "description": "Return config-based catalog (no Redis dependency)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "include_unlisted",
            "in": "query",
            "description": "Include unlisted sportsbooks",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "include_inactive",
            "in": "query",
            "description": "Include inactive sportsbooks (zero events)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of sportsbooks",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Sportsbook"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "draftkings",
                      "name": "draftkings",
                      "display_name": "DraftKings",
                      "is_sharp": false,
                      "has_live_odds": true,
                      "has_player_props": true,
                      "regions": [
                        "US"
                      ],
                      "requires_tier": "free",
                      "status": "active",
                      "event_count": 320,
                      "last_update": "2026-03-09T14:22:00Z",
                      "unlisted": false
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/sportsbooks/{bookId}": {
      "get": {
        "operationId": "getSportsbook",
        "summary": "Get sportsbook by ID",
        "description": "Returns details for a single sportsbook.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "bookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "draftkings"
          }
        ],
        "responses": {
          "200": {
            "description": "Sportsbook details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Sportsbook"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/markets": {
      "get": {
        "operationId": "listMarkets",
        "summary": "List market types",
        "description": "Returns available market types with descriptions, examples, and event counts.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of market types",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Market"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "moneyline",
                      "name": "Moneyline",
                      "description": "Bet on which team will win the game outright",
                      "hasLine": false,
                      "examples": [
                        "Lakers -150",
                        "Celtics +130"
                      ],
                      "event_count": 312,
                      "selection_count": 1840,
                      "sports": [
                        "basketball",
                        "football",
                        "baseball",
                        "hockey"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/teams": {
      "get": {
        "operationId": "listTeams",
        "summary": "List teams",
        "description": "Returns teams aggregated from current odds snapshots.",
        "tags": [
          "Reference Data"
        ],
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "query",
            "description": "Filter by sport",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "description": "Filter by league",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Search team names (partial match)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of teams",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Team"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "boston-celtics",
                      "name": "Boston Celtics",
                      "sport": "basketball",
                      "leagues": [
                        "nba"
                      ],
                      "aliases": [
                        "Celtics"
                      ],
                      "event_count": 3,
                      "live_count": 1
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "List events",
        "description": "Returns events aggregated from current odds snapshots. Supports filtering by sport, league, live status, team name, date, and text search.\n\n**Authentication required.**\n",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/has_score"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/date"
          },
          {
            "$ref": "#/components/parameters/q"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of events",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Data-Delay": {
                "$ref": "#/components/headers/X-Data-Delay"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Event"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "nba-20260309-lal-bos",
                      "external_ids": {
                        "draftkings": "123456",
                        "fanduel": "789012"
                      },
                      "sport": "basketball",
                      "league": "nba",
                      "home_team": "Boston Celtics",
                      "away_team": "Los Angeles Lakers",
                      "start_time": "2026-03-09T19:30:00Z",
                      "status": "upcoming",
                      "is_live": false,
                      "book_count": 12,
                      "markets": [
                        "moneyline",
                        "point_spread",
                        "total_points",
                        "player_prop"
                      ],
                      "books": [
                        "betmgm",
                        "caesars",
                        "draftkings",
                        "fanduel"
                      ]
                    }
                  ],
                  "pagination": {
                    "limit": 50,
                    "offset": 0,
                    "has_more": false,
                    "next_offset": null
                  },
                  "meta": {
                    "count": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events/{eventId}": {
      "get": {
        "operationId": "getEvent",
        "summary": "Get event by ID",
        "description": "Returns details for a single event.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "nba-20260309-lal-bos"
          }
        ],
        "responses": {
          "200": {
            "description": "Event details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Event"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/events/{eventId}/markets": {
      "get": {
        "operationId": "getEventMarkets",
        "summary": "Get markets for an event",
        "description": "Returns available market types for a specific event.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of markets for the event",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/events/{eventId}/odds": {
      "get": {
        "operationId": "getEventOdds",
        "summary": "Get odds for an event",
        "description": "Returns odds for a specific event, optionally filtered by sportsbook and market.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sportsbook",
            "in": "query",
            "description": "Filter by sportsbook (comma-separated)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by market type (comma-separated)",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated odds for the event",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Odds"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/odds": {
      "get": {
        "operationId": "listOdds",
        "summary": "List odds",
        "description": "Returns odds across all sportsbooks and events. Supports extensive filtering, sorting, field selection, and grouping.\n\n**Sort options:** `odds_american`, `odds_decimal`, `probability`, `timestamp`, `event_start_time`, `sportsbook`, `sport`, `league`. Prefix with `-` for descending.\n\n**Field selection:** Use `fields` to return only specific fields (e.g., `fields=id,odds_american,sportsbook`).\n",
        "tags": [
          "Odds"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/add_sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/date"
          },
          {
            "$ref": "#/components/parameters/q"
          },
          {
            "$ref": "#/components/parameters/min_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field. Prefix with `-` for descending (e.g., `-odds_american`).",
            "schema": {
              "type": "string",
              "enum": [
                "odds_american",
                "-odds_american",
                "odds_decimal",
                "-odds_decimal",
                "probability",
                "-probability",
                "timestamp",
                "-timestamp",
                "event_start_time",
                "-event_start_time",
                "sportsbook",
                "-sportsbook",
                "sport",
                "-sport",
                "league",
                "-league"
              ]
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated list of fields to return",
            "schema": {
              "type": "string"
            },
            "example": "id,sportsbook,odds_american,odds_decimal"
          },
          {
            "name": "group_by",
            "in": "query",
            "description": "Group results by event",
            "schema": {
              "type": "string",
              "enum": [
                "event"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated odds",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Data-Delay": {
                "$ref": "#/components/headers/X-Data-Delay"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Odds"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/odds/best": {
      "get": {
        "operationId": "getBestOdds",
        "summary": "Best odds per selection",
        "description": "Returns the best available odds for each selection across all sportsbooks.",
        "tags": [
          "Odds"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated best odds",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Odds"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/odds/comparison": {
      "get": {
        "operationId": "compareOdds",
        "summary": "Compare odds across books",
        "description": "Returns side-by-side odds comparison for a specific event across all sportsbooks.",
        "tags": [
          "Odds"
        ],
        "parameters": [
          {
            "name": "event",
            "in": "query",
            "required": true,
            "description": "Event ID to compare",
            "schema": {
              "type": "string"
            },
            "example": "nba-20260309-lal-bos"
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by market type (comma-separated)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Odds comparison",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/Odds"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/odds/batch": {
      "post": {
        "operationId": "batchOdds",
        "summary": "Batch odds lookup",
        "description": "Returns odds for multiple events in a single request. Batch size limits vary by tier:\n- Free: 5 events\n- Hobby: 20 events\n- Pro: 50 events\n- Sharp/Enterprise: 100 events\n",
        "tags": [
          "Odds"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchOddsRequest"
              },
              "example": {
                "event_ids": [
                  "nba-20260309-lal-bos",
                  "nba-20260309-gsw-mia"
                ],
                "sportsbook": "draftkings",
                "market": "moneyline"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Odds for requested events",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/Odds"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/odds/delta": {
      "get": {
        "operationId": "getOddsDelta",
        "summary": "Odds changes since timestamp",
        "description": "Returns odds that have changed since the given ISO 8601 timestamp.",
        "tags": [
          "Odds"
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": true,
            "description": "ISO 8601 timestamp to get changes since",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-03-09T14:00:00Z"
          },
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Odds changed since the given timestamp",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Odds"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/opportunities/ev": {
      "get": {
        "operationId": "listEVOpportunities",
        "summary": "List +EV opportunities",
        "description": "Returns positive expected value betting opportunities. Requires **Pro** tier or higher.\n\nEV is calculated by devigging sharp book lines (typically Pinnacle) and comparing\nagainst other sportsbook prices. When multiple sportsbooks are +EV on the same\nselection, a separate opportunity is returned for each book, ranked by EV%.\n\n**Sort options:** `ev` (default), `odds`, `confidence`, `start_time`, `kelly`.\n",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/min_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds"
          },
          {
            "$ref": "#/components/parameters/min_ev"
          },
          {
            "$ref": "#/components/parameters/max_ev"
          },
          {
            "$ref": "#/components/parameters/min_market_width"
          },
          {
            "$ref": "#/components/parameters/max_market_width"
          },
          {
            "$ref": "#/components/parameters/max_odds_age"
          },
          {
            "$ref": "#/components/parameters/date_range"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": [
                "ev",
                "-ev",
                "odds",
                "-odds",
                "confidence",
                "-confidence",
                "start_time",
                "-start_time",
                "kelly",
                "-kelly"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated EV opportunities",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EVOpportunity"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "a1b2c3d4e5f67890",
                      "game_id": "nba-20260309-lal-bos",
                      "ev_percentage": 4.2,
                      "odds_american": 135,
                      "odds_decimal": 2.35,
                      "no_vig_odds": 125,
                      "selection": "Los Angeles Lakers",
                      "market": "moneyline",
                      "line": null,
                      "sportsbook": "draftkings",
                      "game": "Los Angeles Lakers @ Boston Celtics",
                      "sport": "basketball",
                      "league": "nba",
                      "home_team": "Boston Celtics",
                      "away_team": "Los Angeles Lakers",
                      "start_time": "2026-03-09T19:30:00Z",
                      "is_live": false,
                      "market_width": 6.5,
                      "fair_probability": 0.444,
                      "devig_method": "multiplicative",
                      "sharp_book": "pinnacle",
                      "external_event_id": "dk-123456",
                      "selection_id": "sel-789",
                      "detected_at": "2026-03-09T14:22:15Z",
                      "confidence_score": 78,
                      "kelly_percent": 0.031,
                      "book_count": 8,
                      "arb_available": false,
                      "arb_profit": null,
                      "is_player_prop": false,
                      "player_name": null,
                      "stat_category": null,
                      "possibly_stale": false,
                      "oldest_odds_age_seconds": 12,
                      "warnings": []
                    }
                  ],
                  "pagination": {
                    "limit": 50,
                    "offset": 0,
                    "has_more": false,
                    "next_offset": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/opportunities/arbitrage": {
      "get": {
        "operationId": "listArbitrageOpportunities",
        "summary": "List arbitrage opportunities",
        "description": "Returns arbitrage (sure-bet) opportunities across sportsbooks. Requires **Hobby** tier or higher.\n\n**Sort options:** `profit` (default), `start_time`, `sport`.\n\n**Format:** Set `format=csv` for CSV export. Set `group=best` to return only the highest-profit arb per event.\n",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/min_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds"
          },
          {
            "$ref": "#/components/parameters/min_profit"
          },
          {
            "$ref": "#/components/parameters/max_odds_age"
          },
          {
            "$ref": "#/components/parameters/date_range"
          },
          {
            "name": "format",
            "in": "query",
            "description": "Response format",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          },
          {
            "name": "group",
            "in": "query",
            "description": "Grouping mode",
            "schema": {
              "type": "string",
              "enum": [
                "best"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": [
                "profit",
                "-profit",
                "start_time",
                "-start_time",
                "sport",
                "-sport"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated arbitrage opportunities",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ArbitrageOpportunity"
                          }
                        }
                      }
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/opportunities/middles": {
      "get": {
        "operationId": "listMiddleOpportunities",
        "summary": "List middle opportunities",
        "description": "Returns middle betting opportunities where both sides of a line can win simultaneously. Requires **Pro** tier or higher.\n\n**Sort options:** `quality` (default), `ev`, `probability`, `middle_size`.\n",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/min_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds"
          },
          {
            "$ref": "#/components/parameters/min_size"
          },
          {
            "$ref": "#/components/parameters/max_odds_age"
          },
          {
            "$ref": "#/components/parameters/date_range"
          },
          {
            "name": "state",
            "in": "query",
            "description": "US state code for deep link generation",
            "schema": {
              "type": "string",
              "default": "pa"
            },
            "example": "nj"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": [
                "quality",
                "-quality",
                "ev",
                "-ev",
                "probability",
                "-probability",
                "middle_size",
                "-middle_size"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated middle opportunities",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/MiddleOpportunity"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/opportunities/middles/{id}": {
      "get": {
        "operationId": "getMiddleOpportunity",
        "summary": "Get middle opportunity by ID",
        "description": "Returns details for a single middle opportunity. Requires **Pro** tier or higher.",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "16-character hex opportunity ID",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{16}$"
            },
            "example": "a1b2c3d4e5f67890"
          }
        ],
        "responses": {
          "200": {
            "description": "Middle opportunity details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/MiddleOpportunity"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/opportunities/middles/summary": {
      "get": {
        "operationId": "getMiddlesSummary",
        "summary": "Middles summary by sport/league",
        "description": "Returns aggregated middle opportunity counts by sport and league. Requires **Pro** tier or higher.",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          }
        ],
        "responses": {
          "200": {
            "description": "Summary of middle opportunities",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          }
        }
      }
    },
    "/opportunities/low_hold": {
      "get": {
        "operationId": "listLowHoldOpportunities",
        "summary": "List low-hold opportunities",
        "description": "Returns markets with unusually low bookmaker hold (vig), indicating efficient pricing. Requires **Hobby** tier or higher.\n\n**Sort options:** `hold` (default), `market`, `sport`.\n",
        "tags": [
          "Opportunities"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/team"
          },
          {
            "$ref": "#/components/parameters/min_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds"
          },
          {
            "$ref": "#/components/parameters/max_odds_age"
          },
          {
            "$ref": "#/components/parameters/date_range"
          },
          {
            "name": "max_hold",
            "in": "query",
            "description": "Maximum hold percentage to return",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "US state code for deep link generation",
            "schema": {
              "type": "string",
              "default": "pa"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": [
                "hold",
                "-hold",
                "market",
                "-market",
                "sport",
                "-sport"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated low-hold opportunities",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/LowHoldOpportunity"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/stream": {
      "get": {
        "operationId": "stream",
        "summary": "Real-time SSE stream",
        "description": "Server-Sent Events stream for real-time odds and opportunity updates. Requires streaming access (WebSocket add-on, Enterprise tier, or active trial).\n\nUse `api_key` query parameter for authentication since `EventSource` cannot set headers.\n\n## Channels\n\n| Channel | Description |\n|---------|-------------|\n| `opportunities` | EV, arbitrage, middles, low-hold updates (default) |\n| `odds` | Raw odds changes |\n| `all` | Both odds and opportunities |\n| `gamestate` | Live game state updates (Enterprise only) |\n\n## Event Types\n\n| Event | Payload | Description |\n|-------|---------|-------------|\n| `connected` | `{filters, channels}` | Stream established |\n| `snapshot` | Array of items | Initial data dump (one per type) |\n| `snapshot:complete` | `{}` | All snapshots sent |\n| `odds:update` | `Odds` | Odds changed |\n| `odds:removed` | `{id, sportsbook}` | Selection removed |\n| `ev:detected` | `EVOpportunity` | New +EV opportunity |\n| `ev:expired` | `{id}` | EV opportunity gone |\n| `arb:detected` | `ArbitrageOpportunity` | New arbitrage |\n| `arb:expired` | `{id}` | Arbitrage gone |\n| `middles:detected` | `MiddleOpportunity` | New middle |\n| `middles:expired` | `{id}` | Middle gone |\n| `low_hold:detected` | `LowHoldOpportunity` | New low-hold |\n| `low_hold:expired` | `{id}` | Low-hold gone |\n| `gamestate:snapshot` | `{sport, events}` | Initial game state |\n| `gamestate:update` | `{sport, event_id, ...}` | Game state changed |\n| `heartbeat` | `{ts}` | Keep-alive (every 30s) |\n| `error` | `{message}` | Recoverable error |\n\nSupports `Last-Event-ID` header for reconnection.\n",
        "tags": [
          "Streaming"
        ],
        "security": [
          {
            "ApiKeyQuery": []
          },
          {
            "ApiKeyHeader": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "api_key",
            "in": "query",
            "description": "API key (for EventSource which cannot set headers)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel",
            "in": "query",
            "description": "Stream channel",
            "schema": {
              "type": "string",
              "enum": [
                "opportunities",
                "odds",
                "all",
                "gamestate"
              ],
              "default": "opportunities"
            }
          },
          {
            "$ref": "#/components/parameters/sport"
          },
          {
            "$ref": "#/components/parameters/league"
          },
          {
            "$ref": "#/components/parameters/sportsbook"
          },
          {
            "$ref": "#/components/parameters/market"
          },
          {
            "$ref": "#/components/parameters/event"
          },
          {
            "$ref": "#/components/parameters/live"
          },
          {
            "$ref": "#/components/parameters/min_ev"
          },
          {
            "$ref": "#/components/parameters/min_profit"
          },
          {
            "name": "state",
            "in": "query",
            "description": "US state code for deep link generation",
            "schema": {
              "type": "string",
              "default": "pa"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SSE event stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-Sent Events stream. Each event has `event:` type, `data:` JSON payload, and `id:` for reconnection."
                },
                "example": "event: connected\ndata: {\"filters\":{\"channel\":\"opportunities\",\"sport\":null},\"session_id\":\"abc123\"}\nid: 1709993400000-1\n\nevent: ev:detected\ndata: {\"id\":\"a1b2c3d4e5f67890\",\"ev_percentage\":4.2,\"sportsbook\":\"draftkings\",\"selection\":\"Los Angeles Lakers\",\"market\":\"moneyline\",\"sport\":\"basketball\",\"league\":\"nba\"}\nid: 1709993400000-2\n\nevent: heartbeat\ndata: {\"ts\":1709993430000}\nid: 1709993430000-3\n"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Streaming access required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "streaming_not_available",
                    "message": "Streaming requires WebSocket add-on or Enterprise tier",
                    "docs": "https://sharpapi.io/pricing"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/account": {
      "get": {
        "operationId": "getAccount",
        "summary": "Get account info",
        "description": "Returns API key details, tier, limits, feature access, and add-on status.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "Account information",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Account"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "key": {
                      "id": "key_abc123",
                      "tier": "pro",
                      "user_id": "user_xyz"
                    },
                    "limits": {
                      "requests_per_minute": 300,
                      "max_streams": 0,
                      "odds_delay_seconds": 0,
                      "max_books": 15
                    },
                    "features": {
                      "ev": true,
                      "arbitrage": true,
                      "middles": true,
                      "streaming": false
                    },
                    "addons": []
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/account/usage": {
      "get": {
        "operationId": "getAccountUsage",
        "summary": "Get usage statistics",
        "description": "Returns request counts, rate limit status, and stream usage for the current billing period.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "Usage statistics",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Usage"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "requests": {
                      "today": 1420,
                      "this_week": 8200,
                      "this_month": 32500,
                      "limit": {
                        "per_minute": 300,
                        "remaining": 285,
                        "resets_at": "2026-03-09T14:23:00Z"
                      }
                    },
                    "streams": {
                      "active": 0,
                      "max": 0
                    },
                    "period": {
                      "start": "2026-03-01T00:00:00Z",
                      "end": "2026-03-31T23:59:59Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/account/keys": {
      "get": {
        "operationId": "listApiKeys",
        "summary": "List API keys",
        "description": "Returns all API keys for the authenticated user.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "List of API keys",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ApiKey"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "key_abc123",
                      "id_masked": "...key_abc123",
                      "name": "Production Key",
                      "tier": "pro",
                      "is_active": true,
                      "created_at": "2026-01-15T10:00:00Z",
                      "updated_at": "2026-03-01T00:00:00Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "summary": "Create a new API key",
        "description": "Creates a new API key for the authenticated user. The key value is returned only once in the response.\nMaximum keys per tier: Free/Hobby/Pro = 1, Sharp = 2, Enterprise = custom.\n",
        "tags": [
          "Account"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Optional display name for the key"
                  }
                }
              },
              "example": {
                "name": "My new key"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New API key created (key value shown only once)",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "id",
                            "key",
                            "tier"
                          ],
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "key": {
                              "type": "string",
                              "description": "The API key value (shown only once)"
                            },
                            "name": {
                              "type": "string",
                              "nullable": true
                            },
                            "tier": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "key_new456",
                    "key": "sk_live_abc123def456",
                    "name": "My new key",
                    "tier": "pro"
                  },
                  "meta": {
                    "warning": "This is the only time the key value will be shown. Store it securely."
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/account/keys/{keyId}": {
      "delete": {
        "operationId": "deleteApiKey",
        "summary": "Revoke an API key",
        "description": "Permanently revokes a specific API key. Users can only revoke their own keys.",
        "tags": [
          "Account"
        ],
        "parameters": [
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "description": "The Unkey key ID to revoke",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Key revoked successfully",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "revoked": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "key_abc123",
                    "revoked": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/account/keys/{keyId}/rotate": {
      "post": {
        "operationId": "rotateApiKey",
        "summary": "Rotate an API key",
        "description": "Creates a new API key and revokes the old one. Supports an optional grace period\n(0-72 hours) to keep the old key valid during migration.\n",
        "tags": [
          "Account"
        ],
        "parameters": [
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "description": "The Unkey key ID to rotate",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "gracePeriodHours": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 72,
                    "default": 0,
                    "description": "Hours to keep the old key valid (0 = immediate revocation)"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Optional name for the new key"
                  }
                }
              },
              "example": {
                "gracePeriodHours": 24,
                "name": "Rotated production key"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key rotated successfully (new key value shown only once)",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "new_key_id",
                            "new_key",
                            "old_key_id"
                          ],
                          "properties": {
                            "new_key_id": {
                              "type": "string"
                            },
                            "new_key": {
                              "type": "string",
                              "description": "The new API key value (shown only once)"
                            },
                            "old_key_id": {
                              "type": "string"
                            },
                            "old_key_expires_at": {
                              "type": "string",
                              "format": "date-time",
                              "nullable": true,
                              "description": "When the old key expires (null if immediate)"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/deeplinks/batch": {
      "post": {
        "operationId": "batchDeepLinks",
        "summary": "Batch deep link lookup",
        "description": "Returns redirect paths for multiple odds IDs or opportunity hash IDs. Resolved IDs return a redirect path, unresolvable IDs return null. Requires **Hobby** tier or higher.",
        "tags": [
          "Deep Links"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ids"
                ],
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 500
                  },
                  "state": {
                    "type": "string",
                    "default": "pa"
                  }
                }
              },
              "example": {
                "ids": [
                  "17336125542407",
                  "77b0749a1faae425"
                ],
                "state": "nj"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Redirect paths for each ID",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string",
                        "nullable": true,
                        "description": "Redirect path (e.g. /api/v1/deeplink/{id}) or null if unavailable"
                      }
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "data": {
                    "17336125542407": "/api/v1/deeplink/17336125542407",
                    "77b0749a1faae425": null
                  },
                  "updated_at": "2026-02-11T12:00:15.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          }
        }
      }
    },
    "/deeplink/{id}": {
      "get": {
        "operationId": "redirectDeepLink",
        "summary": "Deep link redirect",
        "description": "Redirects to a sportsbook deep link. No authentication required.\nReturns a 302 redirect to the sportsbook URL, or 404 if the link cannot be generated.\n",
        "tags": [
          "Deep Links"
        ],
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Opportunity or event identifier",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "US state code",
            "schema": {
              "type": "string",
              "default": "pa"
            }
          },
          {
            "name": "book",
            "in": "query",
            "description": "Target sportsbook",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "game_id",
            "in": "query",
            "description": "Game/event ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "home",
            "in": "query",
            "description": "Home team name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "away",
            "in": "query",
            "description": "Away team name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fallback",
            "in": "query",
            "description": "Fallback URL if deep link cannot be generated",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to sportsbook",
            "headers": {
              "Location": {
                "description": "Sportsbook deep link URL",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "404": {
            "description": "Deep link not found"
          }
        }
      }
    },
    "/futures": {
      "get": {
        "operationId": "listFuturesMarkets",
        "summary": "List futures markets",
        "description": "Returns available futures markets with metadata, merged across all sportsbooks. Public endpoint.",
        "tags": [
          "Futures"
        ],
        "security": [
          {},
          {
            "ApiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "query",
            "description": "Filter by sport",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "description": "Filter by league",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "future_type",
            "in": "query",
            "description": "Filter by futures type",
            "schema": {
              "type": "string",
              "enum": [
                "TEAM",
                "PLAYER",
                "OVER_UNDER",
                "YES_NO"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of futures markets",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/FutureMarket"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "market_id": "championship_winner",
                      "display_name": "NBA Championship Winner",
                      "sport": "basketball",
                      "league": "nba",
                      "future_type": "TEAM",
                      "selection_count": 30,
                      "books_available": [
                        "draftkings",
                        "fanduel",
                        "betmgm"
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/futures/odds": {
      "get": {
        "operationId": "listFuturesOdds",
        "summary": "Get futures odds",
        "description": "Returns cross-book odds for a specific futures market. Requires authentication.",
        "tags": [
          "Futures"
        ],
        "parameters": [
          {
            "name": "future_id",
            "in": "query",
            "required": true,
            "description": "Futures market ID",
            "schema": {
              "type": "string"
            },
            "example": "championship_winner"
          },
          {
            "name": "sportsbook",
            "in": "query",
            "description": "Filter by sportsbook (comma-separated)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated futures odds",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/FutureOdds"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "selection": "Boston Celtics",
                      "sportsbook": "draftkings",
                      "odds_american": 350,
                      "odds_decimal": 4.5,
                      "probability": 0.2222,
                      "future_type": "TEAM",
                      "future_market_id": "championship_winner",
                      "future_market_name": "NBA Championship Winner",
                      "sport": "basketball",
                      "league": "nba",
                      "event_start_time": "2026-06-15T00:00:00Z",
                      "timestamp": "2026-03-09T14:00:00Z"
                    }
                  ],
                  "pagination": {
                    "limit": 100,
                    "offset": 0,
                    "has_more": false,
                    "next_offset": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/gamestate": {
      "get": {
        "operationId": "listAllGameState",
        "summary": "Live game state for every sport",
        "description": "Returns aggregated live game state (scores, periods, clocks, situational data) for every sport with active events. Merged across sportsbooks with a consensus-based algorithm so a single misbehaving book can't skew the result. Requires **Enterprise** tier.",
        "tags": [
          "Game State"
        ],
        "responses": {
          "200": {
            "description": "Live game state keyed by sport then event_id",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "Map of sport name to a map of event_id → EventGameState",
                          "additionalProperties": {
                            "type": "object",
                            "additionalProperties": {
                              "$ref": "#/components/schemas/EventGameState"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "data": {
                    "soccer": {
                      "argentina_-_primera_division_bocajuniors_defensayjusticia_2026-04-23": {
                        "home_team": "Defensa y Justicia",
                        "away_team": "Boca Juniors",
                        "sport": "soccer",
                        "league": "argentina_-_primera_division",
                        "home_score": 0,
                        "away_score": 1,
                        "game_period": "2H",
                        "game_clock": "49:06",
                        "is_live": true,
                        "possession": "away",
                        "corners_home": 1,
                        "corners_away": 0,
                        "primary_book": "draftkings",
                        "book_count": 6
                      }
                    },
                    "baseball": {
                      "mlb_redsox_yankees_2026-04-23": {
                        "home_team": "New York Yankees",
                        "away_team": "Boston Red Sox",
                        "sport": "baseball",
                        "league": "mlb",
                        "home_score": 2,
                        "away_score": 1,
                        "game_period": "T5",
                        "is_live": true,
                        "primary_book": "fliff",
                        "book_count": 9
                      }
                    }
                  },
                  "updated_at": "2026-04-23T23:55:01.234Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          }
        }
      }
    },
    "/gamestate/{sport}": {
      "get": {
        "operationId": "getGameStateForSport",
        "summary": "Live game state for a single sport",
        "description": "Returns aggregated live game state for events in one sport. Response shape matches `GET /gamestate` but `data` contains a single key (the path `sport`). Unknown sports return an empty `data` object, never 404. Requires **Enterprise** tier.",
        "tags": [
          "Game State"
        ],
        "parameters": [
          {
            "name": "sport",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "soccer"
            },
            "description": "Atlas sport id. Case-insensitive. Known values: `baseball`, `basketball`, `football`, `hockey`, `soccer`, `tennis`, `table_tennis`, `cricket`, `esports`, `snooker`, `other`."
          }
        ],
        "responses": {
          "200": {
            "description": "Live game state for the requested sport (envelope identical to `/gamestate`, just scoped to one sport)",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DataEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "Map with a single key (the path sport) whose value is a map of event_id → EventGameState.",
                          "additionalProperties": {
                            "type": "object",
                            "additionalProperties": {
                              "$ref": "#/components/schemas/EventGameState"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "data": {
                    "soccer": {
                      "chile_-_primera_division_concepcion_palestino_2026-04-24": {
                        "home_team": "Palestino",
                        "away_team": "Concepción",
                        "sport": "soccer",
                        "league": "chile_-_primera_division",
                        "home_score": 0,
                        "away_score": 0,
                        "is_live": true,
                        "primary_book": "unibet",
                        "book_count": 1,
                        "stale": true
                      }
                    }
                  },
                  "updated_at": "2026-04-23T23:55:01.234Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierRestricted"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key passed in the `X-API-Key` header"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key passed as a Bearer token in the `Authorization` header"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "API key as query parameter (for SSE/EventSource only)"
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum requests allowed per minute",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in the current window",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp (ms) when the rate limit window resets",
        "schema": {
          "type": "integer"
        }
      },
      "X-Data-Delay": {
        "description": "Odds data delay in seconds (0 = real-time)",
        "schema": {
          "type": "integer"
        }
      },
      "X-Request-Id": {
        "description": "Unique request identifier",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "sport": {
        "name": "sport",
        "in": "query",
        "description": "Filter by sport (comma-separated)",
        "schema": {
          "type": "string"
        },
        "example": "basketball"
      },
      "league": {
        "name": "league",
        "in": "query",
        "description": "Filter by league (comma-separated)",
        "schema": {
          "type": "string"
        },
        "example": "nba"
      },
      "sportsbook": {
        "name": "sportsbook",
        "in": "query",
        "description": "Filter by sportsbook (comma-separated)",
        "schema": {
          "type": "string"
        },
        "example": "draftkings,fanduel"
      },
      "add_sportsbook": {
        "name": "add_sportsbook",
        "in": "query",
        "description": "Add sportsbook(s) to the default set for your tier (can appear multiple times)",
        "schema": {
          "type": "string"
        }
      },
      "market": {
        "name": "market",
        "in": "query",
        "description": "Filter by market type (comma-separated)",
        "schema": {
          "type": "string"
        },
        "example": "moneyline,point_spread"
      },
      "event": {
        "name": "event",
        "in": "query",
        "description": "Filter by event ID (comma-separated). Alias `event_id` also accepted.",
        "schema": {
          "type": "string"
        }
      },
      "live": {
        "name": "live",
        "in": "query",
        "description": "Filter by live status",
        "schema": {
          "type": "boolean"
        }
      },
      "has_score": {
        "name": "has_score",
        "in": "query",
        "description": "Filter events that have (true) or lack (false) game state scores",
        "schema": {
          "type": "boolean"
        }
      },
      "team": {
        "name": "team",
        "in": "query",
        "description": "Filter by team name (partial match)",
        "schema": {
          "type": "string"
        }
      },
      "date": {
        "name": "date",
        "in": "query",
        "description": "Filter by event date (YYYY-MM-DD)",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "example": "2026-03-09"
      },
      "q": {
        "name": "q",
        "in": "query",
        "description": "Full-text search on team names",
        "schema": {
          "type": "string"
        }
      },
      "min_odds": {
        "name": "min_odds",
        "in": "query",
        "description": "Minimum American odds",
        "schema": {
          "type": "number"
        }
      },
      "max_odds": {
        "name": "max_odds",
        "in": "query",
        "description": "Maximum American odds",
        "schema": {
          "type": "number"
        }
      },
      "min_ev": {
        "name": "min_ev",
        "in": "query",
        "description": "Minimum EV percentage",
        "schema": {
          "type": "number",
          "default": 0
        }
      },
      "max_ev": {
        "name": "max_ev",
        "in": "query",
        "description": "Maximum EV percentage",
        "schema": {
          "type": "number"
        }
      },
      "min_profit": {
        "name": "min_profit",
        "in": "query",
        "description": "Minimum profit percentage",
        "schema": {
          "type": "number",
          "default": 0.5
        }
      },
      "min_size": {
        "name": "min_size",
        "in": "query",
        "description": "Minimum middle size",
        "schema": {
          "type": "number",
          "default": 0.5
        }
      },
      "min_market_width": {
        "name": "min_market_width",
        "in": "query",
        "description": "Minimum market width",
        "schema": {
          "type": "number"
        }
      },
      "max_market_width": {
        "name": "max_market_width",
        "in": "query",
        "description": "Maximum market width",
        "schema": {
          "type": "number"
        }
      },
      "max_odds_age": {
        "name": "max_odds_age",
        "in": "query",
        "description": "Maximum odds age in seconds (filters out stale odds)",
        "schema": {
          "type": "number"
        }
      },
      "date_range": {
        "name": "date_range",
        "in": "query",
        "description": "Date range filter",
        "schema": {
          "type": "string",
          "enum": [
            "today",
            "tomorrow",
            "week"
          ]
        }
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "description": "Maximum results per page",
        "schema": {
          "type": "integer",
          "default": 50,
          "minimum": 0,
          "maximum": 500
        }
      },
      "offset": {
        "name": "offset",
        "in": "query",
        "description": "Number of results to skip",
        "schema": {
          "type": "integer",
          "default": 0,
          "minimum": 0,
          "maximum": 5000
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "missing": {
                "summary": "Missing API key",
                "value": {
                  "error": {
                    "code": "missing_api_key",
                    "message": "API key required",
                    "docs": "https://sharpapi.io/docs/authentication"
                  }
                }
              },
              "invalid": {
                "summary": "Invalid API key",
                "value": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Invalid API key",
                    "docs": "https://sharpapi.io/docs/authentication"
                  }
                }
              }
            }
          }
        }
      },
      "TierRestricted": {
        "description": "Feature requires a higher subscription tier",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "tier_restricted",
                "message": "EV opportunities requires pro tier or higher",
                "tier": "hobby",
                "required_tier": "pro",
                "docs": "https://sharpapi.io/pricing"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Retry-After": {
            "description": "Seconds until the rate limit resets",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "rate_limited",
                "message": "Rate limit exceeded",
                "retry_after": 1709993460000,
                "docs": "https://sharpapi.io/docs/rate-limits"
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "invalid_request",
                "message": "Missing required parameter"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "not_found",
                "message": "Resource not found"
              }
            }
          }
        }
      }
    },
    "schemas": {
      "PaginatedEnvelope": {
        "type": "object",
        "description": "Standard shape for paginated list responses. No `success` flag — HTTP status codes indicate success/failure.",
        "required": [
          "data",
          "pagination",
          "updated_at"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {}
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Server emit time (RFC 3339)."
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "limit",
          "offset",
          "has_more",
          "next_offset"
        ],
        "properties": {
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          },
          "next_offset": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "missing_api_key",
                  "invalid_api_key",
                  "unauthorized",
                  "forbidden",
                  "tier_restricted",
                  "rate_limited",
                  "invalid_request",
                  "validation_error",
                  "not_found",
                  "streaming_not_available",
                  "stream_limit_exceeded",
                  "service_unavailable",
                  "internal_error"
                ],
                "description": "Machine-readable error code"
              },
              "message": {
                "type": "string",
                "description": "Human-readable error message"
              },
              "docs": {
                "type": "string",
                "format": "uri",
                "description": "Link to relevant documentation"
              },
              "tier": {
                "type": "string",
                "description": "Current subscription tier"
              },
              "required_tier": {
                "type": "string",
                "description": "Minimum tier required for this feature"
              },
              "retry_after": {
                "type": "integer",
                "description": "Unix timestamp (ms) when request can be retried"
              },
              "max_books": {
                "type": "integer"
              },
              "requested_books": {
                "type": "integer"
              }
            }
          }
        }
      },
      "HealthCheck": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded",
              "down"
            ]
          },
          "latency_ms": {
            "type": "number"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Sport": {
        "type": "object",
        "required": [
          "id",
          "name",
          "event_count",
          "live_count",
          "leagues"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "basketball"
          },
          "name": {
            "type": "string",
            "example": "Basketball"
          },
          "event_count": {
            "type": "integer"
          },
          "live_count": {
            "type": "integer"
          },
          "leagues": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "League": {
        "type": "object",
        "required": [
          "id",
          "name",
          "sport",
          "event_count",
          "live_count"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "nba"
          },
          "name": {
            "type": "string",
            "example": "NBA"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "event_count": {
            "type": "integer"
          },
          "live_count": {
            "type": "integer"
          }
        }
      },
      "Sportsbook": {
        "type": "object",
        "required": [
          "id",
          "name",
          "display_name",
          "is_sharp",
          "has_live_odds",
          "has_player_props",
          "regions",
          "requires_tier",
          "status",
          "event_count"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "draftkings"
          },
          "name": {
            "type": "string",
            "example": "draftkings"
          },
          "display_name": {
            "type": "string",
            "example": "DraftKings"
          },
          "is_sharp": {
            "type": "boolean"
          },
          "has_live_odds": {
            "type": "boolean"
          },
          "has_player_props": {
            "type": "boolean"
          },
          "regions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "requires_tier": {
            "type": "string",
            "enum": [
              "free",
              "sharp"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive",
              "limited"
            ]
          },
          "event_count": {
            "type": "integer"
          },
          "last_update": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "unlisted": {
            "type": "boolean"
          }
        }
      },
      "Market": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "hasLine"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "moneyline"
          },
          "name": {
            "type": "string",
            "example": "Moneyline"
          },
          "description": {
            "type": "string"
          },
          "hasLine": {
            "type": "boolean"
          },
          "examples": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "event_count": {
            "type": "integer",
            "nullable": true
          },
          "selection_count": {
            "type": "integer",
            "nullable": true
          },
          "sports": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Team": {
        "type": "object",
        "required": [
          "id",
          "name",
          "sport",
          "leagues",
          "aliases",
          "event_count",
          "live_count"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "boston-celtics"
          },
          "name": {
            "type": "string",
            "example": "Boston Celtics"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "leagues": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "event_count": {
            "type": "integer"
          },
          "live_count": {
            "type": "integer"
          }
        }
      },
      "Event": {
        "type": "object",
        "required": [
          "id",
          "sport",
          "league",
          "home_team",
          "away_team",
          "start_time",
          "status",
          "is_live",
          "book_count",
          "markets",
          "books"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "nba-20260309-lal-bos"
          },
          "external_ids": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Sportsbook-native event IDs keyed by book"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "league": {
            "type": "string",
            "example": "nba"
          },
          "home_team": {
            "type": "string",
            "example": "Boston Celtics"
          },
          "away_team": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "start_time": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "upcoming",
              "live",
              "ended"
            ]
          },
          "is_live": {
            "type": "boolean"
          },
          "book_count": {
            "type": "integer"
          },
          "markets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "books": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "game_state": {
            "$ref": "#/components/schemas/EventGameState"
          }
        }
      },
      "EventGameState": {
        "type": "object",
        "description": "Aggregated live game state for a single event, merged across the sportsbooks covering it. Scores are consensus-selected; temporal fields use sport-aware clock direction; situational fields priority-fill from a fixed book ranking. Every field is optional except the always-present core set — sport coverage varies, so e.g. tennis rows carry sets_home/server while hockey rows carry power_play.",
        "required": [
          "home_team",
          "away_team",
          "sport",
          "league",
          "home_score",
          "away_score",
          "is_live",
          "primary_book",
          "book_count"
        ],
        "properties": {
          "home_team": {
            "type": "string",
            "description": "Normalized home team name."
          },
          "away_team": {
            "type": "string",
            "description": "Normalized away team name."
          },
          "sport": {
            "type": "string",
            "description": "Atlas sport id (e.g. `baseball`, `soccer`)."
          },
          "league": {
            "type": "string",
            "description": "Atlas league id (e.g. `mlb`, `england_-_premier_league`)."
          },
          "home_score": {
            "type": "integer",
            "description": "Current home score in the natural unit for the sport (runs, points, goals, sets — tennis uses summed set points)."
          },
          "away_score": {
            "type": "integer",
            "description": "Current away score."
          },
          "is_live": {
            "type": "boolean",
            "description": "Always `true` for events returned by this endpoint."
          },
          "primary_book": {
            "type": "string",
            "description": "The sportsbook whose scores were selected by the merge. Consensus-respecting — if ≥2 books agree on a score the highest-priority book in that group wins."
          },
          "book_count": {
            "type": "integer",
            "description": "Number of sportsbooks that contributed live state for this event at merge time."
          },
          "game_period": {
            "type": "string",
            "description": "Current period. Sport-specific format: `T5` (MLB top 5), `Q3` (NBA Q3), `2H` (soccer 2nd half), `P2` (NHL P2), `S2` (tennis set 2), `FT` (full time)."
          },
          "game_clock": {
            "type": "string",
            "description": "Game clock. Countup format (`49:06`) for soccer; countdown format (`5:42`) for basketball/hockey/football."
          },
          "possession": {
            "type": "string",
            "enum": [
              "home",
              "away"
            ],
            "description": "Which team has possession (team sports) or is receiving (tennis)."
          },
          "server": {
            "type": "string",
            "enum": [
              "home",
              "away"
            ],
            "description": "Tennis only — current server."
          },
          "last_play": {
            "type": "string",
            "description": "Sport-specific last-play description."
          },
          "is_timeout": {
            "type": "boolean",
            "description": "`true` during a timeout."
          },
          "fouls_home": {
            "type": "integer",
            "description": "Team fouls (basketball, soccer)."
          },
          "fouls_away": {
            "type": "integer"
          },
          "corners_home": {
            "type": "integer",
            "description": "Soccer only."
          },
          "corners_away": {
            "type": "integer"
          },
          "yellow_cards_home": {
            "type": "integer",
            "description": "Soccer only."
          },
          "yellow_cards_away": {
            "type": "integer"
          },
          "red_cards_home": {
            "type": "integer",
            "description": "Soccer only."
          },
          "red_cards_away": {
            "type": "integer"
          },
          "power_play": {
            "type": "string",
            "enum": [
              "home",
              "away"
            ],
            "description": "Hockey only — which team is on the power play."
          },
          "sets_home": {
            "type": "integer",
            "description": "Tennis only — sets won."
          },
          "sets_away": {
            "type": "integer"
          },
          "hits_home": {
            "type": "integer",
            "description": "Baseball only."
          },
          "hits_away": {
            "type": "integer"
          },
          "home_pitcher": {
            "type": "string",
            "description": "Baseball only — starting pitcher display name."
          },
          "away_pitcher": {
            "type": "string"
          },
          "wickets_home": {
            "type": "integer",
            "description": "Cricket only — dismissals."
          },
          "wickets_away": {
            "type": "integer"
          },
          "overs": {
            "type": "number",
            "description": "Cricket only."
          },
          "batting_team": {
            "type": "string",
            "enum": [
              "home",
              "away"
            ],
            "description": "Cricket only."
          },
          "stale": {
            "type": "boolean",
            "description": "Only emitted when `true`. Indicates the `primary_book`'s livestate key TTL fell below the aggregator's freshness threshold (~10s) at merge time — scores reflect the last known values; the book has gone quiet. Absence of the field means fresh."
          },
          "aggregator_stale": {
            "type": "boolean",
            "description": "Only emitted when `true`. Indicates the SharpAPI aggregator itself hasn't advanced the gen counter for this event's sport in more than ~30s. Broader signal than `stale` — suggests a pipeline hiccup, not a single-book issue."
          }
        }
      },
      "Odds": {
        "type": "object",
        "required": [
          "id",
          "sportsbook",
          "sportsbook_name",
          "event_id",
          "sport",
          "league",
          "home_team",
          "away_team",
          "market_type",
          "selection",
          "selection_type",
          "odds_american",
          "odds_decimal",
          "probability",
          "event_start_time",
          "is_live",
          "timestamp"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "sportsbook": {
            "type": "string",
            "example": "draftkings"
          },
          "sportsbook_name": {
            "type": "string",
            "example": "DraftKings"
          },
          "event_id": {
            "type": "string"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "league": {
            "type": "string",
            "example": "nba"
          },
          "home_team": {
            "type": "string",
            "example": "Boston Celtics"
          },
          "away_team": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "market_type": {
            "type": "string",
            "example": "moneyline"
          },
          "selection": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "selection_type": {
            "type": "string",
            "example": "away"
          },
          "odds_american": {
            "type": "number",
            "example": 135
          },
          "odds_decimal": {
            "type": "number",
            "example": 2.35
          },
          "probability": {
            "type": "number",
            "description": "Implied probability (0-1)",
            "example": 0.4255
          },
          "line": {
            "type": "number",
            "nullable": true,
            "description": "Point spread or total line (null for moneyline)",
            "example": null
          },
          "event_start_time": {
            "type": "string",
            "format": "date-time"
          },
          "is_live": {
            "type": "boolean"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When these odds were last updated"
          },
          "player_name": {
            "type": "string",
            "nullable": true,
            "description": "Player name (player prop markets only)"
          },
          "stat_category": {
            "type": "string",
            "nullable": true,
            "description": "Stat category (player prop markets only)"
          }
        }
      },
      "BatchOddsRequest": {
        "type": "object",
        "required": [
          "event_ids"
        ],
        "properties": {
          "event_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "description": "Array of event IDs to fetch odds for"
          },
          "sportsbook": {
            "type": "string",
            "description": "Optionally filter by sportsbook"
          },
          "market": {
            "type": "string",
            "description": "Optionally filter by market type"
          }
        }
      },
      "EVOpportunity": {
        "type": "object",
        "required": [
          "id",
          "game_id",
          "ev_percentage",
          "odds_american",
          "odds_decimal",
          "no_vig_odds",
          "selection",
          "market",
          "line",
          "sportsbook",
          "game",
          "sport",
          "league",
          "home_team",
          "away_team",
          "start_time",
          "is_live",
          "market_width",
          "fair_probability",
          "devig_method",
          "sharp_book",
          "external_event_id",
          "selection_id",
          "detected_at",
          "confidence_score",
          "kelly_percent",
          "book_count",
          "arb_available",
          "arb_profit",
          "is_player_prop",
          "player_name",
          "stat_category",
          "possibly_stale",
          "oldest_odds_age_seconds",
          "warnings"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "16-character hex opportunity ID",
            "example": "a1b2c3d4e5f67890"
          },
          "game_id": {
            "type": "string",
            "nullable": true
          },
          "ev_percentage": {
            "type": "number",
            "description": "Expected value as a percentage (e.g., 4.2 = 4.2% EV)",
            "example": 4.2
          },
          "odds_american": {
            "type": "number",
            "example": 135
          },
          "odds_decimal": {
            "type": "number",
            "example": 2.35
          },
          "no_vig_odds": {
            "type": "number",
            "nullable": true,
            "description": "Fair odds with vig removed",
            "example": 125
          },
          "selection": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "market": {
            "type": "string",
            "example": "moneyline"
          },
          "line": {
            "type": "number",
            "nullable": true
          },
          "sportsbook": {
            "type": "string",
            "description": "Sportsbook offering these odds. Multiple entries may exist for the same selection if several books are +EV.",
            "example": "draftkings"
          },
          "game": {
            "type": "string",
            "example": "Los Angeles Lakers @ Boston Celtics"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "league": {
            "type": "string",
            "example": "nba"
          },
          "home_team": {
            "type": "string",
            "nullable": true
          },
          "away_team": {
            "type": "string",
            "nullable": true
          },
          "start_time": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "is_live": {
            "type": "boolean"
          },
          "market_width": {
            "type": "number",
            "nullable": true,
            "description": "Spread between best and worst odds across books"
          },
          "fair_probability": {
            "type": "number",
            "nullable": true,
            "description": "No-vig (devigged) fair probability (0.0 to 1.0)"
          },
          "devig_method": {
            "type": "string",
            "description": "Method used to remove vig",
            "example": "multiplicative"
          },
          "sharp_book": {
            "type": "string",
            "description": "Sharp book used as reference (e.g., pinnacle)",
            "example": "pinnacle"
          },
          "external_event_id": {
            "type": "string",
            "nullable": true,
            "description": "Sportsbook-native event ID for deep linking"
          },
          "selection_id": {
            "type": "string",
            "nullable": true,
            "description": "Sportsbook outcome/selection ID for bet-level deep links"
          },
          "detected_at": {
            "type": "string",
            "format": "date-time"
          },
          "confidence_score": {
            "type": "number",
            "description": "Multi-factor confidence score (0-100)",
            "example": 78
          },
          "kelly_percent": {
            "type": "number",
            "nullable": true,
            "description": "Optimal bet fraction (0.0-1.0) from Kelly criterion"
          },
          "book_count": {
            "type": "integer",
            "description": "Number of books offering this market"
          },
          "arb_available": {
            "type": "boolean",
            "description": "Whether an arbitrage opportunity exists for this market"
          },
          "arb_profit": {
            "type": "number",
            "nullable": true,
            "description": "Arbitrage profit percentage if available"
          },
          "is_player_prop": {
            "type": "boolean"
          },
          "player_name": {
            "type": "string",
            "nullable": true
          },
          "stat_category": {
            "type": "string",
            "nullable": true
          },
          "possibly_stale": {
            "type": "boolean",
            "description": "Whether the odds may be stale"
          },
          "oldest_odds_age_seconds": {
            "type": "number",
            "nullable": true,
            "description": "Age of the oldest odds used in this calculation"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Warning flags (e.g., POTENTIALLY_STALE_ODDS, LIVE_STALE_ODDS, LOW_IMPLIED_TOTAL)"
          }
        }
      },
      "ArbitrageOpportunity": {
        "type": "object",
        "required": [
          "id",
          "event_id",
          "event_name",
          "sport",
          "league",
          "market_type",
          "line",
          "profit_percent",
          "implied_total",
          "start_time",
          "is_live",
          "game_state",
          "is_alternate_line",
          "possibly_stale",
          "oldest_odds_age_seconds",
          "warnings",
          "ev_available",
          "ev_percentage",
          "is_player_prop",
          "player_name",
          "stat_category",
          "estimated_net_profit_percent",
          "legs",
          "detected_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "b2c3d4e5f6789012"
          },
          "event_id": {
            "type": "string"
          },
          "event_name": {
            "type": "string",
            "example": "Los Angeles Lakers @ Boston Celtics"
          },
          "sport": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "market_type": {
            "type": "string",
            "example": "moneyline"
          },
          "line": {
            "type": "number",
            "nullable": true
          },
          "profit_percent": {
            "type": "number",
            "description": "Guaranteed profit percentage before costs",
            "example": 1.8
          },
          "implied_total": {
            "type": "number",
            "description": "Sum of implied probabilities (below 1.0 = arbitrage)",
            "example": 0.982
          },
          "start_time": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "is_live": {
            "type": "boolean"
          },
          "game_state": {
            "$ref": "#/components/schemas/OpportunityGameState"
          },
          "is_alternate_line": {
            "type": "boolean"
          },
          "possibly_stale": {
            "type": "boolean"
          },
          "oldest_odds_age_seconds": {
            "type": "number",
            "nullable": true
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "ev_available": {
            "type": "boolean",
            "description": "Whether a +EV opportunity also exists for this market"
          },
          "ev_percentage": {
            "type": "number",
            "nullable": true
          },
          "is_player_prop": {
            "type": "boolean"
          },
          "player_name": {
            "type": "string",
            "nullable": true
          },
          "stat_category": {
            "type": "string",
            "nullable": true
          },
          "estimated_net_profit_percent": {
            "type": "number",
            "description": "Profit percentage after estimated transaction costs"
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArbitrageLeg"
            }
          },
          "detected_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ArbitrageLeg": {
        "type": "object",
        "required": [
          "sportsbook",
          "selection",
          "odds_american",
          "odds_decimal",
          "implied_probability",
          "stake_percent",
          "timestamp",
          "external_event_id",
          "selection_id",
          "market_id"
        ],
        "properties": {
          "sportsbook": {
            "type": "string",
            "example": "draftkings"
          },
          "selection": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "odds_american": {
            "type": "number",
            "example": 135
          },
          "odds_decimal": {
            "type": "number",
            "example": 2.35
          },
          "implied_probability": {
            "type": "number",
            "example": 0.4255
          },
          "stake_percent": {
            "type": "number",
            "description": "Recommended stake as percentage of total bankroll",
            "example": 42.55
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "external_event_id": {
            "type": "string",
            "nullable": true
          },
          "selection_id": {
            "type": "string",
            "nullable": true
          },
          "market_id": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "OpportunityGameState": {
        "type": "object",
        "nullable": true,
        "description": "Simplified game state for opportunity endpoints",
        "properties": {
          "period": {
            "type": "string",
            "nullable": true
          },
          "clock": {
            "type": "string",
            "nullable": true
          },
          "score_home": {
            "type": "integer",
            "nullable": true
          },
          "score_away": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "MiddleOpportunity": {
        "type": "object",
        "required": [
          "id",
          "event_id",
          "event_name",
          "sport",
          "league",
          "market_type",
          "home_team",
          "away_team",
          "start_time",
          "side1",
          "side2",
          "middle_size",
          "middle_numbers",
          "middle_probability",
          "expected_value",
          "roi_percentage",
          "worst_case_loss",
          "best_case_profit",
          "break_even_percent",
          "is_live",
          "is_player_prop",
          "player_name",
          "stat_category",
          "odds_age_seconds",
          "is_guaranteed_profit",
          "guaranteed_roi",
          "key_numbers",
          "key_number_probability",
          "quality_score",
          "market_overround",
          "warnings",
          "is_team_total",
          "team_name",
          "detected_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "event_id": {
            "type": "string"
          },
          "event_name": {
            "type": "string"
          },
          "sport": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "market_type": {
            "type": "string"
          },
          "home_team": {
            "type": "string"
          },
          "away_team": {
            "type": "string"
          },
          "start_time": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "side1": {
            "$ref": "#/components/schemas/MiddleSide"
          },
          "side2": {
            "$ref": "#/components/schemas/MiddleSide"
          },
          "middle_size": {
            "type": "number",
            "description": "Gap between the two lines",
            "example": 2
          },
          "middle_numbers": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "The numbers that fall in the middle"
          },
          "middle_probability": {
            "type": "number",
            "description": "Probability of landing in the middle"
          },
          "expected_value": {
            "type": "number"
          },
          "roi_percentage": {
            "type": "number"
          },
          "worst_case_loss": {
            "type": "number",
            "description": "Maximum loss if the middle doesn't hit"
          },
          "best_case_profit": {
            "type": "number",
            "description": "Profit if the result lands in the middle"
          },
          "break_even_percent": {
            "type": "number"
          },
          "is_live": {
            "type": "boolean"
          },
          "is_player_prop": {
            "type": "boolean"
          },
          "player_name": {
            "type": "string",
            "nullable": true
          },
          "stat_category": {
            "type": "string",
            "nullable": true
          },
          "odds_age_seconds": {
            "type": "number",
            "nullable": true
          },
          "is_guaranteed_profit": {
            "type": "boolean",
            "description": "Whether this middle guarantees profit regardless of outcome"
          },
          "guaranteed_roi": {
            "type": "number",
            "nullable": true
          },
          "key_numbers": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Key numbers in this sport (e.g., 3 and 7 in NFL)"
          },
          "key_number_probability": {
            "type": "number"
          },
          "quality_score": {
            "type": "number",
            "description": "Overall quality score combining multiple factors"
          },
          "market_overround": {
            "type": "number",
            "description": "Combined implied probability of both sides"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_team_total": {
            "type": "boolean"
          },
          "team_name": {
            "type": "string",
            "nullable": true
          },
          "alt_side1": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "book": {
                  "type": "string"
                },
                "odds": {
                  "type": "number"
                }
              }
            },
            "description": "Alternative books offering side 1"
          },
          "alt_side2": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "book": {
                  "type": "string"
                },
                "odds": {
                  "type": "number"
                }
              }
            },
            "description": "Alternative books offering side 2"
          },
          "detected_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MiddleSide": {
        "type": "object",
        "required": [
          "book",
          "selection",
          "line",
          "odds",
          "stake_percent",
          "odds_age_seconds",
          "deep_link"
        ],
        "properties": {
          "book": {
            "type": "string",
            "example": "draftkings"
          },
          "selection": {
            "type": "string",
            "example": "Over 220.5"
          },
          "line": {
            "type": "number",
            "example": 220.5
          },
          "odds": {
            "type": "object",
            "required": [
              "american",
              "decimal",
              "probability",
              "fair_probability"
            ],
            "properties": {
              "american": {
                "type": "number",
                "example": -110
              },
              "decimal": {
                "type": "number",
                "example": 1.909
              },
              "probability": {
                "type": "number",
                "example": 0.5238
              },
              "fair_probability": {
                "type": "number",
                "example": 0.5
              }
            }
          },
          "stake_percent": {
            "type": "number",
            "example": 50
          },
          "odds_age_seconds": {
            "type": "number",
            "nullable": true
          },
          "deep_link": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "LowHoldOpportunity": {
        "type": "object",
        "required": [
          "id",
          "event_id",
          "event_name",
          "sport",
          "league",
          "market_type",
          "line",
          "home_team",
          "away_team",
          "start_time",
          "hold_percentage",
          "side1",
          "side2",
          "side3",
          "is_live",
          "game_state",
          "is_alternate_line",
          "all_books",
          "is_player_prop",
          "player_name",
          "stat_category",
          "confidence",
          "odds_age_seconds",
          "possibly_stale",
          "detected_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "event_id": {
            "type": "string"
          },
          "event_name": {
            "type": "string"
          },
          "sport": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "market_type": {
            "type": "string"
          },
          "line": {
            "type": "number",
            "nullable": true
          },
          "home_team": {
            "type": "string"
          },
          "away_team": {
            "type": "string"
          },
          "start_time": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "hold_percentage": {
            "type": "number",
            "description": "Bookmaker hold (vig) percentage. Lower is better for bettors.",
            "example": 1.2
          },
          "side1": {
            "$ref": "#/components/schemas/LowHoldSide"
          },
          "side2": {
            "$ref": "#/components/schemas/LowHoldSide"
          },
          "side3": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/LowHoldSide"
              }
            ],
            "description": "Third side (3-way markets like soccer moneyline with draw)"
          },
          "is_live": {
            "type": "boolean"
          },
          "game_state": {
            "$ref": "#/components/schemas/OpportunityGameState"
          },
          "is_alternate_line": {
            "type": "boolean"
          },
          "all_books": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All sportsbooks contributing to this opportunity"
          },
          "is_player_prop": {
            "type": "boolean"
          },
          "player_name": {
            "type": "string",
            "nullable": true
          },
          "stat_category": {
            "type": "string",
            "nullable": true
          },
          "confidence": {
            "type": "number",
            "description": "Confidence score (0-100)"
          },
          "odds_age_seconds": {
            "type": "number",
            "description": "Age of the odds in seconds"
          },
          "possibly_stale": {
            "type": "boolean"
          },
          "detected_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LowHoldSide": {
        "type": "object",
        "required": [
          "selection",
          "books",
          "line",
          "odds",
          "deep_links"
        ],
        "properties": {
          "selection": {
            "type": "string",
            "example": "Los Angeles Lakers"
          },
          "books": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sportsbooks offering the best odds on this side"
          },
          "line": {
            "type": "number",
            "nullable": true
          },
          "odds": {
            "type": "object",
            "required": [
              "american",
              "decimal",
              "implied_probability",
              "fair_probability"
            ],
            "properties": {
              "american": {
                "type": "number",
                "example": -108
              },
              "decimal": {
                "type": "number",
                "example": 1.926
              },
              "implied_probability": {
                "type": "number",
                "example": 0.5192
              },
              "fair_probability": {
                "type": "number",
                "example": 0.5
              }
            }
          },
          "deep_links": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            },
            "description": "Deep link URLs keyed by sportsbook"
          }
        }
      },
      "Account": {
        "type": "object",
        "required": [
          "key",
          "limits",
          "features",
          "addons"
        ],
        "properties": {
          "key": {
            "type": "object",
            "required": [
              "id",
              "tier"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "tier": {
                "type": "string",
                "enum": [
                  "free",
                  "hobby",
                  "pro",
                  "sharp",
                  "enterprise"
                ]
              },
              "user_id": {
                "type": "string"
              }
            }
          },
          "limits": {
            "type": "object",
            "required": [
              "requests_per_minute",
              "max_streams",
              "odds_delay_seconds",
              "max_books"
            ],
            "properties": {
              "requests_per_minute": {
                "type": "integer"
              },
              "max_streams": {
                "type": "integer"
              },
              "odds_delay_seconds": {
                "type": "integer"
              },
              "max_books": {
                "type": "integer"
              }
            }
          },
          "features": {
            "type": "object",
            "required": [
              "ev",
              "arbitrage",
              "middles",
              "streaming"
            ],
            "properties": {
              "ev": {
                "type": "boolean"
              },
              "arbitrage": {
                "type": "boolean"
              },
              "middles": {
                "type": "boolean"
              },
              "streaming": {
                "type": "boolean"
              }
            }
          },
          "addons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "streaming_trial": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "eligible": {
                "type": "boolean"
              },
              "used": {
                "type": "boolean"
              },
              "activated_at": {
                "type": "string",
                "format": "date-time"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "remaining_hours": {
                "type": "number"
              }
            }
          }
        }
      },
      "Usage": {
        "type": "object",
        "required": [
          "requests",
          "streams",
          "period"
        ],
        "properties": {
          "requests": {
            "type": "object",
            "required": [
              "today",
              "this_week",
              "this_month",
              "limit"
            ],
            "properties": {
              "today": {
                "type": "integer"
              },
              "this_week": {
                "type": "integer"
              },
              "this_month": {
                "type": "integer"
              },
              "limit": {
                "type": "object",
                "required": [
                  "per_minute",
                  "remaining",
                  "resets_at"
                ],
                "properties": {
                  "per_minute": {
                    "type": "integer"
                  },
                  "remaining": {
                    "type": "integer"
                  },
                  "resets_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              }
            }
          },
          "streams": {
            "type": "object",
            "required": [
              "active",
              "max"
            ],
            "properties": {
              "active": {
                "type": "integer"
              },
              "max": {
                "type": "integer"
              }
            }
          },
          "period": {
            "type": "object",
            "required": [
              "start",
              "end"
            ],
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "required": [
          "id",
          "id_masked",
          "name",
          "tier",
          "is_active",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "id_masked": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "tier": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FutureMarket": {
        "type": "object",
        "required": [
          "market_id",
          "display_name",
          "sport",
          "league",
          "future_type",
          "selection_count"
        ],
        "properties": {
          "market_id": {
            "type": "string",
            "example": "championship_winner"
          },
          "display_name": {
            "type": "string",
            "example": "NBA Championship Winner"
          },
          "sport": {
            "type": "string",
            "example": "basketball"
          },
          "league": {
            "type": "string",
            "example": "nba"
          },
          "future_type": {
            "type": "string",
            "enum": [
              "TEAM",
              "PLAYER",
              "OVER_UNDER",
              "YES_NO"
            ]
          },
          "selection_count": {
            "type": "integer",
            "description": "Number of available selections"
          },
          "books_available": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sportsbooks offering this futures market"
          }
        }
      },
      "FutureOdds": {
        "type": "object",
        "required": [
          "selection",
          "sportsbook",
          "odds_american",
          "odds_decimal",
          "probability",
          "future_type",
          "future_market_id",
          "future_market_name",
          "sport",
          "league",
          "event_start_time",
          "timestamp"
        ],
        "properties": {
          "selection": {
            "type": "string",
            "example": "Boston Celtics"
          },
          "sportsbook": {
            "type": "string",
            "example": "draftkings"
          },
          "odds_american": {
            "type": "number",
            "example": 350
          },
          "odds_decimal": {
            "type": "number",
            "example": 4.5
          },
          "probability": {
            "type": "number",
            "example": 0.2222
          },
          "line": {
            "type": "number",
            "nullable": true
          },
          "future_type": {
            "type": "string"
          },
          "future_market_id": {
            "type": "string"
          },
          "future_market_name": {
            "type": "string"
          },
          "sport": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "event_start_time": {
            "type": "string",
            "format": "date-time"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SplitsGame": {
        "type": "object",
        "description": "Public betting splits for a single event from one source sportsbook.",
        "required": [
          "event_id",
          "sport",
          "league",
          "sportsbook"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "description": "Canonical event ID (joinable with /odds)"
          },
          "sport": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "sportsbook": {
            "type": "string",
            "enum": [
              "draftkings",
              "circa"
            ],
            "description": "Source sportsbook for the splits data."
          },
          "away_team": {
            "type": "string"
          },
          "home_team": {
            "type": "string"
          },
          "spread": {
            "type": "object",
            "description": "Spread market splits. NOTE: `away_odds` and `home_odds` here carry spread *line* values (e.g. -1.5/+1.5), not American odds. Field naming is a known inconsistency vs `/splits/history` which uses `away_line`/`home_line`.",
            "properties": {
              "away_odds": {
                "type": "number"
              },
              "home_odds": {
                "type": "number"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "home": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "home": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              }
            }
          },
          "total": {
            "type": "object",
            "properties": {
              "line": {
                "type": "number"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "over": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "under": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "over": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "under": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              }
            }
          },
          "moneyline": {
            "type": "object",
            "properties": {
              "away_odds": {
                "type": "number",
                "description": "American odds"
              },
              "home_odds": {
                "type": "number",
                "description": "American odds"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "home": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "home": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                }
              }
            }
          },
          "fetched_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SplitsHistoryEntry": {
        "type": "object",
        "description": "A single timestamped splits snapshot for an event from one source.",
        "required": [
          "book",
          "ts",
          "timestamp"
        ],
        "properties": {
          "book": {
            "type": "string",
            "enum": [
              "draftkings",
              "circa"
            ],
            "description": "Source sportsbook. NOTE: this endpoint uses `book`; `/splits` uses `sportsbook` for the same concept (known inconsistency)."
          },
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "Snapshot timestamp (RFC 3339)."
          },
          "timestamp": {
            "type": "number",
            "description": "Snapshot timestamp (Unix seconds, fractional)."
          },
          "spread": {
            "type": "object",
            "properties": {
              "away_line": {
                "type": "number"
              },
              "home_line": {
                "type": "number"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number"
                  },
                  "home": {
                    "type": "number"
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number"
                  },
                  "home": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "total": {
            "type": "object",
            "properties": {
              "line": {
                "type": "number"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "over": {
                    "type": "number"
                  },
                  "under": {
                    "type": "number"
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "over": {
                    "type": "number"
                  },
                  "under": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "moneyline": {
            "type": "object",
            "properties": {
              "away_odds": {
                "type": "number"
              },
              "home_odds": {
                "type": "number"
              },
              "handle_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number"
                  },
                  "home": {
                    "type": "number"
                  }
                }
              },
              "bets_pct": {
                "type": "object",
                "properties": {
                  "away": {
                    "type": "number"
                  },
                  "home": {
                    "type": "number"
                  }
                }
              }
            }
          }
        }
      },
      "DataEnvelope": {
        "type": "object",
        "description": "Standard shape for non-paginated responses. Emitted by endpoints that return a single resource or a small fixed list. No `success` flag — HTTP status codes indicate success/failure.",
        "required": [
          "data",
          "updated_at"
        ],
        "properties": {
          "data": {},
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Server emit time (RFC 3339)."
          }
        }
      }
    }
  }
}
