{
  "openapi": "3.0.0",
  "x-origin": [
    {
      "url": "https://api.odds-api.io/v3/docs/doc.json",
      "format": "swagger",
      "version": "2.0",
      "converter": {
        "url": "https://github.com/mermade/oas-kit",
        "version": "7.0.8"
      }
    }
  ],
  "info": {
    "description": "Odds-API.io is a powerful sports betting odds comparison API, providing real-time data from 450+ bookmakers across 34 sports with near zero latency.\n\n- 450+ bookmakers supported\n- 34 sports including Football, Basketball, Tennis, Esports and more\n- Real-time odds with close to zero latency\n- Pre-match & In-play odds coverage\n- 99.9% uptime for reliability",
    "title": "Odds-API.io - Real-Time Sports Betting Odds API (v3)",
    "contact": {},
    "version": "3.0.0"
  },
  "paths": {
    "/arbitrage-bets": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns prematch arbitrage opportunities where every leg uses one of the specified bookmakers, sorted by profit margin (highest first). Opportunities are refreshed every few seconds and removed as soon as the prices move or the match starts. Margins and stakes use prices after exchange fees, and stakes respect the limits bookmakers report, so totalStake can be below 1000. By default only the best combination per event, market and line is returned; set allCombinations=true for every combination.",
        "tags": [
          "Arbitrage Bets"
        ],
        "summary": "Get arbitrage betting opportunities",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365,SingBet\"",
            "description": "Comma-separated list of bookmakers (e.g. Bet365,SingBet)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "football",
            "description": "Filter by sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "england-premier-league",
            "description": "Filter by league slug (e.g. england-premier-league). Requires sport to also be set.",
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "ML,Spread,Totals",
            "description": "Comma-separated market names to keep, case-insensitive (max 40)",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 1.5,
            "description": "Minimum profitMargin in percent, between 0 and 100 (e.g. 1.5 for 1.5%)",
            "name": "minProfit",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "example": false,
            "description": "Return every bookmaker combination per event, market and line instead of only the best one (default false)",
            "name": "allCombinations",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "example": 50,
            "description": "Maximum number of results (default 50, max 500)",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "example": true,
            "description": "Include event details",
            "name": "includeEventDetails",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.ArbitrageOpportunity"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found (unknown league for the sport)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/bookmakers": {
      "get": {
        "description": "Fetch a list of supported bookmakers with their current status. `status` is `ok`, `degraded` (no odds update for 60+ minutes) or `down` (no odds update for 3+ hours on a book with 100+ active matches). Odds from a `down` bookmaker are left out of every odds endpoint and removed over the WebSocket until it recovers. `reason` is null when `ok`; otherwise `maintenance` (the bookmaker is temporarily offline on its side) or `unavailable` (we temporarily have no fresh odds from this bookmaker).",
        "tags": [
          "Bookmakers"
        ],
        "summary": "Get Bookmakers",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/models.Bookmaker"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "List every bookmaker you can query through Odds-API.io, from sportsbooks to exchanges and prediction markets, with each bookmaker's name, active flag and live feed status."
          }
        }
      }
    },
    "/bookmakers/selected": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Fetch the list of bookmakers selected by the authenticated user",
        "tags": [
          "Bookmakers"
        ],
        "summary": "Get Selected Bookmakers",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get the bookmakers selected on your account. The odds endpoints and WebSocket feed return prices from this selection, so check it before you fetch odds."
          }
        }
      }
    },
    "/bookmakers/selected/clear": {
      "put": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Remove all selected bookmakers for the authenticated user. Rate limited to once every 12 hours; the cooldown may be shorter for newly created accounts.",
        "tags": [
          "Bookmakers"
        ],
        "summary": "Clear Selected Bookmakers",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/bookmakers/selected/select": {
      "put": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Add bookmakers to the authenticated user",
        "tags": [
          "Bookmakers"
        ],
        "summary": "Select Bookmakers",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365,SingBet\"",
            "description": "Comma-separated list of bookmaker names (e.g. Bet365,SingBet)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Add bookmakers to your account's selection with a comma-separated list of names, such as Bet365,SingBet. The odds endpoints and WebSocket use this list."
          }
        }
      }
    },
    "/events": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns events with enhanced filtering and pagination",
        "tags": [
          "Events"
        ],
        "summary": "Get Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"england-premier-league\"",
            "description": "League slug (e.g. england-premier-league)",
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 38,
            "description": "Filter by participant ID (home or away)",
            "name": "participantId",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "example": "\"pending,live\"",
            "description": "Comma-separated event statuses (e.g. pending,live,settled,cancelled)",
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2025-10-28T10:00:00Z\"",
            "description": "Start date/time in RFC3339 format (e.g. 2025-10-28T10:00:00Z)",
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2025-10-28T23:59:59Z\"",
            "description": "End date/time in RFC3339 format (e.g. 2025-10-28T23:59:59Z). If omitted, defaults to 14 days from now.",
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"SingBet\"",
            "description": "Filter by bookmaker name - returns only events that have odds available from this bookmaker (e.g. SingBet)",
            "name": "bookmaker",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 20,
            "description": "Maximum number of events to return. Every response is capped at 5000; use limit + skip to paginate larger ranges.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "example": 0,
            "description": "Number of events to skip (for pagination)",
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.SimpleEventDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "List events for a sport, filtered by league, participant, status, dates or bookmaker. Returns teams, kickoff, status and scores, paged with limit and skip."
          }
        }
      }
    },
    "/events/live": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns all currently live events from all sports with optional sport filter",
        "tags": [
          "Events"
        ],
        "summary": "Get Live Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug to filter by (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.SimpleEventDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get every event in play right now across all sports, or filter by one sport. Each event includes teams, league, live scores, match clock and status."
          }
        }
      }
    },
    "/events/search": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Searches events by team or league name and returns up to 10 results ranked by relevance. By default only upcoming (not yet started, not cancelled) events are searched. Pass status=live to search in-play events instead; live results include current scores and, where available, the match clock.",
        "tags": [
          "Events"
        ],
        "summary": "Search Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Liverpool\"",
            "description": "Search term (min 3 characters)",
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Which events to search: upcoming (default) or live",
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "upcoming",
                "live"
              ],
              "default": "upcoming"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.SimpleEventDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Search events by team or league name and get up to 10 matches ranked by relevance. Upcoming by default; pass status=live for in-play events with scores."
          }
        }
      }
    },
    "/events/{id}": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns a single event by its unique identifier",
        "tags": [
          "Events"
        ],
        "summary": "Get Event by ID",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 123456,
            "description": "Event ID",
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/dto.SimpleEventDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get one event by id: home and away teams, league, sport, kickoff date, status, live scores and match clock, plus how many bookmakers are pricing it."
          }
        }
      }
    },
    "/historical/events": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns finished events for a given sport and league within a date range. Maximum date span is 31 days. Historical data is available from December 2025 onwards.",
        "tags": [
          "Historical"
        ],
        "summary": "Get Historical Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"england-premier-league\"",
            "description": "League slug (e.g. england-premier-league)",
            "name": "league",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-01-01T00:00:00Z\"",
            "description": "Start date in RFC3339 format",
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-01-31T23:59:59Z\"",
            "description": "End date in RFC3339 format",
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.SimpleEventDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get finished events for a sport and league in a date range of up to 31 days, to feed historical odds requests. Data is available from December 2025."
          }
        }
      }
    },
    "/historical/events/search": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Searches finished events by team name across all leagues, optionally scoped to a sport. Maximum date span is 31 days (defaults to the trailing 31 days). Returns up to 100 events, newest first. Historical data is available from December 2025 onwards.",
        "tags": [
          "Historical"
        ],
        "summary": "Search Historical Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Brann\"",
            "description": "Team name fragment, minimum 3 characters",
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-01-01T00:00:00Z\"",
            "description": "Start date in RFC3339 format",
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-01-31T23:59:59Z\"",
            "description": "End date in RFC3339 format",
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.SimpleEventDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Search finished events by team name across all leagues, optionally by sport, over up to 31 days. Returns up to 100 events, newest first, since Dec 2025."
          }
        }
      }
    },
    "/historical/odds": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns closing odds for a finished event from selected bookmakers, including scores.",
        "tags": [
          "Historical"
        ],
        "summary": "Get Historical Odds",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"123456\"",
            "description": "Event ID from /historical/events",
            "name": "eventId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365,SingBet\"",
            "description": "Comma-separated list of bookmaker names (max 30)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"ML,Totals\"",
            "description": "Comma-separated market names to return (e.g. ML,Totals). Returns all markets when omitted.",
            "name": "markets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.EventResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get closing odds for a finished event from the bookmakers you choose, with final scores included. Filter by market to pull closing lines for backtesting."
          }
        }
      }
    },
    "/historical/closing-lines": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns closing odds for every settled event across one or more leagues in a date range, in a single request. Paid plans only.",
        "tags": [
          "Historical"
        ],
        "summary": "Get Historical Closing Lines",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"england-premier-league,spain-la-liga\"",
            "description": "Comma-separated league slugs (max 10)",
            "name": "leagues",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-01-01T00:00:00Z\"",
            "description": "Start date in RFC3339 format",
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"2026-12-31T23:59:59Z\"",
            "description": "End date in RFC3339 format. Maximum 366 days after from, so a full season fits in one sweep.",
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"ML,Totals\"",
            "description": "Comma-separated market names",
            "name": "markets",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365,Unibet\"",
            "description": "Comma-separated list of bookmaker names (max 30)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 100,
            "description": "Maximum number of events to return. Every response is capped at 100; use limit + skip to paginate.",
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "example": 0,
            "description": "Number of events to skip (for pagination)",
            "name": "skip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.EventResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get closing odds for every settled event across one or more leagues in a date range in a single request, filtered by market and bookmaker. Paid plans only."
          }
        }
      }
    },
    "/leagues": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns a list of leagues (name, slug, event count) for a specified sport",
        "tags": [
          "Leagues"
        ],
        "summary": "Get Leagues",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": false,
            "description": "If true, include leagues without active events",
            "name": "all",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.LeagueResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "List the leagues for a sport with each league's name, slug and event count. Filter events by slug, or set all=true to add leagues with no active events."
          }
        }
      }
    },
    "/odds": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns odds comparison for a specific event from selected bookmakers.",
        "tags": [
          "Odds"
        ],
        "summary": "Get Event Odds",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"123456\"",
            "description": "Event ID",
            "name": "eventId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365,Unibet\"",
            "description": "Comma-separated list of bookmaker names (max 30)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated market names to keep, case-insensitive (max 40)",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "ML,Spread,Totals"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.EventResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get odds for one event from your chosen bookmakers in one response, with every market each bookmaker offers, its prices and a link to the event page."
          }
        }
      }
    },
    "/odds/movements": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns the prematch odds movements for one market line of an event from a bookmaker: the opening price, the latest price and recent price changes (how many are kept depends on the bookmaker feed). Market and bookmaker names are case-insensitive. A 404 explains what is missing and lists the markets or lines that do have history. History is recorded only for a fixed set of bookmakers: 10BET, 12bet, 1xbet, 22Bet, 888Sport, BC.Game, Bet365, Betano, Betclic FR, Betfair Exchange, Betfair Sportsbook, Betinia DK, BetMGM, Betsson, BetVictor, Betway, Bovada, Bwin ES, Bwin IT, CloudBet, ComeOn, Coolbet, DanskeSpil, DraftKings, Duel, Eurobet IT, FanDuel, FB Sports, GG.bet, Goldbet IT, Interwetten, Kalshi, Kambi, Ladbrokes, M88, Marathonbet, NetBet, NordicBet, Norsk Tipping, Novibet GR, ON Sharp, Paddy Power, Pamestoixima, Polymarket, Rollbit, Roobet, Sbobet, Sharp Exchange, SingBet, Sisal IT, Snai IT, SportyBet, Stake, Stoiximan, Superbet, Tipico DE, Tipsport.cz, Unibet, Unibet FR, Vbet, Veikkaus, William Hill, Winamax FR, and selected sharp books. Requesting a bookmaker outside this set returns a 404.",
        "tags": [
          "Odds"
        ],
        "summary": "Get Odds Movements",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"123456\"",
            "description": "Event ID",
            "name": "eventId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Bookmaker name, case-insensitive (e.g. Bet365, SingBet, Bet365 (no latency))",
            "name": "bookmaker",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Market name, case-insensitive (e.g. ML, Spread, Totals, Both Teams To Score)",
            "name": "market",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Handicap line (e.g. 0.5, -1.25, 2.5). Leave it out for the main line of Spread and Totals markets, where each entry's hdp shows the line at that time, or for markets without a line (ML, Draw No Bet, Both Teams To Score)",
            "name": "marketLine",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.HandicapMovementsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get prematch odds movements for one market line from one bookmaker: opening price, latest price and recent changes, for a fixed set of tracked bookmakers."
          }
        }
      }
    },
    "/odds/multi": {
      "get": {
        "description": "Returns odds comparison for up to 10 events from selected bookmakers (counts as only 1 request).",
        "tags": [
          "Odds"
        ],
        "summary": "Get Odds for Multiple Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated list of up to 10 Event IDs",
            "name": "eventIds",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated list of bookmaker names (max 30)",
            "name": "bookmakers",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated market names to keep, case-insensitive (max 40)",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "ML,Spread,Totals"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.EventResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get odds for up to 10 events from your chosen bookmakers in one call, counted as a single request, with the same markets as the single-event odds endpoint."
          }
        }
      }
    },
    "/odds/updated": {
      "get": {
        "description": "Returns updated event odds for a specific bookmaker since a given UNIX timestamp (max 90 seconds old). The response is a delta: each event carries only the market groups whose `updatedAt` is at or after `since`, and an event with no changed market group is omitted entirely. Merge responses by event and market name; a market that is absent has not changed, and a withdrawn market is not signalled here (re-read the event with `/odds`, or use the WebSocket feed).",
        "tags": [
          "Odds"
        ],
        "summary": "Get updated event odds since a given timestamp",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Unix timestamp (max 90 seconds old)",
            "name": "since",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Bookmaker name (e.g. Bet365). The response uses the same name; `bookmaker=Bet365` also returns a `Bet365 (no latency)` key, as `/odds/multi` does.",
            "name": "bookmaker",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Sport name (e.g. Football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Max events to return (default and maximum 10000)",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000
            }
          },
          {
            "description": "Comma-separated market names to keep, case-insensitive (max 40). Required from 19 October 2026: a call without it, or where none of the names exist, returns 400. Valid names: /v3/markets?sport=<sport>",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "ML,Spread,Totals"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Server-Time": {
                "description": "Unix seconds captured on the server just before the query ran",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Next-Since": {
                "description": "Value to pass as `since` on the next call. X-Server-Time minus 10 seconds when the response was not truncated by `limit`, so odds that become visible a few seconds after they were stamped are not skipped (the overlap can re-send recent updates; merge them by event and market); otherwise the unix-second floor of the last returned event's `updated_at`. Accepted as `since` while it is no more than 100 seconds old, so drain truncated pages promptly",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Unknown-Markets": {
                "description": "Requested market names that do not exist, when some but not all are unknown",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.EventResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get odds from one bookmaker for events updated since a UNIX timestamp up to 90 seconds old, so you can poll for changes instead of refetching every event."
          }
        }
      }
    },
    "/participants": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns participants (teams) for a specified sport",
        "tags": [
          "Participants"
        ],
        "summary": "Get Participants",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Chelsea\"",
            "description": "Search term to filter by name",
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.ParticipantDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "List the teams and players for a sport with their ids and names, search by name, and get game and short codes for esports teams. Use ids to filter events."
          }
        }
      }
    },
    "/participants/{id}": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns a single participant by its unique identifier",
        "tags": [
          "Participants"
        ],
        "summary": "Get Participant by ID",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 38,
            "description": "Participant ID",
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/dto.ParticipantDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get one team or player by participant id, with name and sport, plus game and short code for esports teams. Use it to resolve homeId and awayId on events."
          }
        }
      }
    },
    "/sports": {
      "get": {
        "description": "Returns a list of sports with name and slug",
        "tags": [
          "Sports"
        ],
        "summary": "Get Sports",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.SportResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "List every sport available through Odds-API.io with its name and slug. Use the slug as the sport parameter on events, leagues and participants requests."
          }
        }
      }
    },
    "/dropping-odds": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns odds that have dropped significantly from their opening values. Data is pre-computed and updated every ~30 seconds. Results are sorted by the selected time window's drop percentage (descending). Pagination metadata is returned in response headers (X-Total-Count, X-Page, X-Per-Page, X-Updated-At).\n\n**Data source selection:**\n- If both `sport` and `league` are provided → reads league-specific data (all entries for that league)\n- If only `sport` is provided → reads sport-level data (top 200 per sport)\n- If neither → reads global data (top 500 across all sports)\n\n**Note:** This endpoint requires a paid plan (Starter or above). Free plan users will receive a 403 error.\n\n**Note:** `leagues` and `league` are mutually exclusive. `leagues` fetches from the sport- or global-level dataset and filters server-side.",
        "tags": [
          "Dropping Odds"
        ],
        "summary": "Get Dropping Odds",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "football",
            "description": "Sport name or slug (e.g. Football or football)",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "england-premier-league",
            "description": "League slug (e.g. england-premier-league). Requires sport param. Mutually exclusive with leagues.",
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "england-premier-league,spain-la-liga",
            "description": "Comma-separated league slugs to filter by multiple leagues at once (e.g. england-premier-league,spain-la-liga). Mutually exclusive with league.",
            "name": "leagues",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "Spread,Totals",
            "description": "Comma-separated market names to filter by (case-insensitive). Supported: ML, Spread, Totals, Spread HT, Totals HT, Totals 1Q, Spread 1Q, Team Total Home, Team Total Away, First 5 Innings ML, First 5 Innings Spread, First 5 Innings Totals, Corners Spread, Corners Totals, Corners Spread HT, Corners Totals HT, Bookings Spread, Bookings Totals, Player Props",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "opening",
            "description": "Time window for drop filtering and sorting. Default: opening",
            "name": "timeWindow",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "opening",
                "12h",
                "24h",
                "48h"
              ],
              "default": "opening"
            }
          },
          {
            "example": 5,
            "description": "Minimum drop percentage for the selected time window. Default: 0",
            "name": "minDrop",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0
            }
          },
          {
            "example": 50,
            "description": "Maximum results per page (default 50, max 200)",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          },
          {
            "example": 1,
            "description": "Page number, 1-indexed (default 1)",
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "example": true,
            "description": "Include event details (home, away, date, sport, league). Default: false",
            "name": "includeEventDetails",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Total-Count": {
                "description": "Total number of entries matching the filters",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Page": {
                "description": "Current page number",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Per-Page": {
                "description": "Number of results per page",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Updated-At": {
                "description": "Timestamp of the last pipeline run (unix milliseconds)",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.DroppingOddsEntry"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get odds that dropped sharply from their opening price, sorted by drop percentage for the chosen time window and refreshed about every 30 seconds."
          }
        }
      }
    },
    "/value-bets": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns value bets for a specific bookmaker with optional match info. Updated every 5 seconds.",
        "tags": [
          "Value Bets"
        ],
        "summary": "Get Value Bets",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "\"Bet365\"",
            "description": "Bookmaker name (e.g. Bet365)",
            "name": "bookmaker",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "baseball",
            "description": "Filter by sport name or slug (e.g. Baseball or baseball). Optional.",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "usa-mlb",
            "description": "Filter by league slug (e.g. usa-mlb). Requires sport to also be set.",
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": true,
            "description": "Include event details",
            "name": "includeEventDetails",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/dto.EventValueBet"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get value bets for one bookmaker: prices above a fair-odds estimate with expected value per outcome, filtered by sport or league, updated every 5 seconds."
          }
        }
      }
    },
    "/participants/{id}/logo": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns the team/participant crest as a PNG image, served from the Odds-API domain. Logos are cached server-side; responses carry Cache-Control: public, max-age=86400. Returns 404 when no logo exists for the participant.",
        "tags": [
          "Participants"
        ],
        "summary": "Get Participant Logo",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": 38,
            "description": "Participant ID",
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PNG image",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway: transient upstream failure, retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get a team or participant crest as a PNG image served from the Odds-API domain and cached for a day. Returns 404 when the participant has no logo."
          }
        }
      }
    },
    "/mappings": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Maps our events and selections to a bookmaker's own identifiers, so our prices can be matched to the bookmaker's own markets. For Polymarket, `marketId` is the conditionId and `outcomeId` is the CLOB token id. For Kalshi, `marketId` is the contract ticker and `outcomeId` is `yes` or `no`. Each row carries our event's `home`, `away`, `date`, `sport` and `league`.\n\nModes:\n- `eventId`, or `eventIds` with up to 10 ids\n- `marketId`, or `marketIds` with up to 10 ids, optionally with `outcomeId`\n- `outcomeId` alone\n- bulk sync: `bookmaker` with none of the above. Returns every mapping for upcoming and live linked events as `{ \"data\": [...], \"nextCursor\": \"...\" }`. Pass `nextCursor` back as `cursor` until it is `null`.\n\nEvery mode returns `{data, nextCursor}`; `nextCursor` is null for lookups. `market` and `active` narrow every mode; `sport`, `league`, `limit` and `cursor` apply to bulk sync only. When `outcomeId` alone matches outcomes in more than one market (Kalshi outcome ids are `yes` and `no`), the request returns 400 and `marketId` must be added. `market`, `hdp` and `side` use our event's orientation, the same as `/v3/odds`. A mapping stays listed with `active: false` after the bookmaker withdraws the outcome. A batch or bulk call counts as one request. Available on paid plans; the bookmaker must be in your selection.",
        "tags": [
          "Mappings"
        ],
        "summary": "Get Native ID Mappings",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "Polymarket",
            "description": "Bookmaker name",
            "name": "bookmaker",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "71515842",
            "description": "Our event id. Returns every mapping of this event.",
            "name": "eventId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "71515842,71515900",
            "description": "Comma-separated list of up to 10 of our event ids. Use instead of `eventId`.",
            "name": "eventIds",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The bookmaker's market id (Polymarket conditionId, Kalshi contract ticker). Can be combined with `outcomeId`.",
            "name": "marketId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "KXNFLGAME-26OCT04BUFNE-BUF,KXNFLGAME-26OCT04BUFNE-NE",
            "description": "Comma-separated list of up to 10 bookmaker market ids. Use instead of `marketId`; can be combined with `outcomeId`.",
            "name": "marketIds",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The bookmaker's outcome id (Polymarket CLOB token id, Kalshi `yes` or `no`). For Kalshi, pass it together with `marketId`.",
            "name": "outcomeId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "Spread",
            "description": "Only this market, by its exact name as served in `/v3/odds` (case-sensitive).",
            "name": "market",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "`true` for outcomes the bookmaker still lists, `false` for withdrawn ones. Default: both.",
            "name": "active",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "example": "american-football",
            "description": "Bulk sync only: sport slug or name.",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "usa-nfl",
            "description": "Bulk sync only: league slug. Requires `sport`.",
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Bulk sync only: rows per page.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1000,
              "minimum": 1,
              "maximum": 5000
            }
          },
          {
            "description": "Bulk sync only: the `nextCursor` of the previous page.",
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK. data holds the mappings; nextCursor is set only in bulk sync while more pages remain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.NativeIDMappingPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request Also returned when a lookup matches more than 5000 mappings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found (unknown league in bulk sync)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Map our events and selections to a bookmaker's own ids, such as Polymarket condition and token ids or Kalshi tickers, by event, market or bulk sync."
          }
        }
      }
    },
    "/markets": {
      "get": {
        "description": "Returns all available markets per sport. Use `shape` to parse a market's odds and `prematch`/`live` to see where it's offered. No API key required.",
        "tags": [
          "Markets"
        ],
        "summary": "Get Markets",
        "parameters": [
          {
            "example": "\"football\"",
            "description": "Sport name or slug (e.g. Football or football). Omit for all sports keyed by slug.",
            "name": "sport",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "With `sport`: markets for that sport. Without: all sports keyed by slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.MarketsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown sport slug",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Catalogue warming up; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/odds/summary": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Best, average, median, worst and margin-free fair price per market line across bookmakers, for odds comparison pages. A bookmaker counts only while its prices are updating (a change within 5 minutes before kickoff, 60 seconds live). Exchanges are reported separately. Available on Growth plans and above. Free, Solo and Starter plans receive a sample response with demo set to true and an X-OddsAPI-Demo: true header.",
        "tags": [
          "Odds"
        ],
        "summary": "Get Odds Summary",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Event ID",
            "name": "eventId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "\"123456\""
          },
          {
            "description": "Comma-separated market names, case-insensitive (default ML,Spread,Totals, max 20)",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "main (default) returns each ladder market's main line; all returns every line priced by at least 3 bookmakers",
            "name": "lines",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Restrict the summary to these bookmakers. Each must be in your selected bookmakers",
            "name": "bookmakers",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Add the best exchange back price per outcome in a separate exchanges block",
            "name": "includeExchanges",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.EventSummary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Best, average, median, worst and margin-free fair price per market line across bookmakers for one event, for odds comparison pages. Growth plans and up."
          }
        }
      }
    },
    "/odds/summary/multi": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "The odds summary for up to 10 events in one request, counted as one request. Events that are not found are left out. Available on Growth plans and above. Free, Solo and Starter plans receive sample responses with demo set to true and an X-OddsAPI-Demo: true header.",
        "tags": [
          "Odds"
        ],
        "summary": "Get Odds Summary for Multiple Events",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated event IDs, up to 10",
            "name": "eventIds",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Comma-separated market names, case-insensitive (default ML,Spread,Totals, max 20)",
            "name": "markets",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "main (default) or all",
            "name": "lines",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Restrict the summary to these bookmakers. Each must be in your selected bookmakers",
            "name": "bookmakers",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Add the best exchange back price per outcome in a separate exchanges block",
            "name": "includeExchanges",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/controllers.EventSummary"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "The odds summary for up to 10 events in one call, counted as one request: best, average, median, worst and fair price per line. Growth plans and above."
          }
        }
      }
    },
    "/settlements": {
      "get": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Returns the settlement record for up to 50 events: status, whether the result is final, and the final scores. Every id gets an answer, including cancelled and not yet resulted events. Paid plans only.",
        "tags": [
          "Settlement"
        ],
        "summary": "Get Settlements",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "example": "74919888,73722728",
            "description": "Comma-separated event ids (1 to 50)",
            "name": "eventIds",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.SettlementsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Paid plans only",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Storage unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Get the settlement record for up to 50 events: status, whether the result is final and the final scores, including cancelled events. Paid plans only."
          }
        }
      }
    },
    "/settlements/grade": {
      "post": {
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Grades up to 50 bet selections against final results. Each selection is the event id, market name, side and, where the market has one, the line (hdp) and label exactly as served on /odds. Returns won, lost, void, half_won, half_lost, pending or ungradeable per selection, with a reason for void, pending and ungradeable answers (reason is null for won, lost, half_won and half_lost). Paid plans only.",
        "tags": [
          "Settlement"
        ],
        "summary": "Grade Selections",
        "parameters": [
          {
            "description": "API key for authentication",
            "name": "apiKey",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Selections to grade. At most 64 KB.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/controllers.GradeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.GradesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Paid plans only",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Storage unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/controllers.ErrorResponse"
                }
              }
            }
          }
        },
        "x-mint": {
          "metadata": {
            "description": "Grade up to 50 bet selections against final results and get won, lost, void, half won, half lost, pending or ungradeable for each one. Paid plans only."
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://api.odds-api.io/v3"
    }
  ],
  "components": {
    "schemas": {
      "controllers.ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "Error message"
          }
        }
      },
      "controllers.EventResponse": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "awayId": {
            "type": "integer"
          },
          "bookmakerIds": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "bookmakers": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/dto.MultiMarketDto"
              }
            }
          },
          "date": {
            "type": "string"
          },
          "home": {
            "type": "string"
          },
          "homeId": {
            "type": "integer"
          },
          "id": {
            "type": "integer"
          },
          "league": {
            "$ref": "#/components/schemas/controllers.League"
          },
          "scores": {
            "$ref": "#/components/schemas/dto.Score"
          },
          "sport": {
            "$ref": "#/components/schemas/controllers.Sport"
          },
          "status": {
            "type": "string"
          },
          "urls": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "controllers.HandicapMovement": {
        "type": "object",
        "properties": {
          "away": {
            "type": "number"
          },
          "draw": {
            "type": "number"
          },
          "hdp": {
            "type": "string"
          },
          "home": {
            "type": "number"
          },
          "max": {
            "type": "integer"
          },
          "timestamp": {
            "type": "integer"
          }
        }
      },
      "controllers.HandicapMovementsResponse": {
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": "string"
          },
          "eventid": {
            "type": "string"
          },
          "latest": {
            "$ref": "#/components/schemas/controllers.HandicapMovement"
          },
          "movements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.HandicapMovement"
            }
          },
          "opening": {
            "$ref": "#/components/schemas/controllers.HandicapMovement"
          }
        }
      },
      "controllers.League": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Premier League"
          },
          "slug": {
            "type": "string",
            "example": "premier-league"
          }
        }
      },
      "controllers.LeagueResponse": {
        "type": "object",
        "properties": {
          "eventsCount": {
            "type": "integer",
            "example": 32
          },
          "name": {
            "type": "string",
            "example": "England - Premier League"
          },
          "slug": {
            "type": "string",
            "example": "england-premier-league"
          }
        }
      },
      "controllers.MarketInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Spread",
            "description": "Market name, as it appears in /odds responses."
          },
          "shape": {
            "type": "string",
            "enum": [
              "moneyline",
              "line",
              "outcomes",
              "yesno",
              "labelled"
            ],
            "example": "line",
            "description": "How to parse the odds. `moneyline`: home/away (+draw on 3-way markets). `line`: one entry per line, with hdp and over/under or home/away. `outcomes`: fixed outcomes (1X/12/X2, odd/even). `yesno`: yes/no prices. `labelled`: one price per label (\"2-1\", \"1st Half\", a player name)."
          },
          "period": {
            "type": "string",
            "enum": [
              "match",
              "first-half",
              "second-half",
              "quarter",
              "set",
              "game",
              "inning"
            ],
            "example": "match",
            "description": "Which part of the event the market covers."
          },
          "prematch": {
            "type": "boolean",
            "example": true,
            "description": "Offered pre-match."
          },
          "live": {
            "type": "boolean",
            "example": true,
            "description": "Offered in-play."
          }
        }
      },
      "controllers.MarketsResponse": {
        "type": "object",
        "properties": {
          "sport": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "example": "Football"
              },
              "slug": {
                "type": "string",
                "example": "football"
              }
            }
          },
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.MarketInfo"
            }
          }
        }
      },
      "controllers.Sport": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Football"
          },
          "slug": {
            "type": "string",
            "example": "football"
          }
        }
      },
      "controllers.SportResponse": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Football"
          },
          "slug": {
            "type": "string",
            "example": "football"
          }
        }
      },
      "dto.ArbitrageLeg": {
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": "string",
            "example": "Bet365"
          },
          "bookmakerFixtureId": {
            "type": "string",
            "description": "The bookmaker's own event id, when known. Not present on every response."
          },
          "href": {
            "type": "string",
            "description": "Link to the event on the bookmaker, or \"N/A\" when none is known.",
            "example": "https://www.bet365.com/..."
          },
          "odds": {
            "type": "string",
            "description": "Decimal odds",
            "example": "2.08"
          },
          "netOdds": {
            "type": "string",
            "description": "Price after exchange fees (for example exchange commission or prediction-market taker fees). Only present when fees apply; profitMargin, impliedProbability and optimalStakes use this price.",
            "example": "2.026"
          },
          "maxStake": {
            "type": "number",
            "description": "Stake limit reported by the bookmaker for this price, when known. optimalStakes never exceed it.",
            "example": 250
          },
          "oddsUpdatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Last time we wrote this bookmaker price. May be absent.",
            "example": "2026-10-21T09:40:12Z"
          },
          "side": {
            "type": "string",
            "enum": [
              "home",
              "away",
              "draw",
              "over",
              "under"
            ],
            "example": "home"
          }
        }
      },
      "dto.ArbitrageOpportunity": {
        "type": "object",
        "properties": {
          "event": {
            "description": "Only included if includeEventDetails=true",
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.EventInfo"
              }
            ]
          },
          "eventId": {
            "type": "integer",
            "example": 123456
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When this combination first appeared",
            "example": "2026-10-20T18:30:02Z"
          },
          "id": {
            "type": "string",
            "description": "{eventId}-{market}[-{hdp}] followed by {bookmaker}-{side} for each leg",
            "example": "123456-ML-Bet365-home-SingBet-away"
          },
          "impliedProbability": {
            "type": "number",
            "description": "Sum of 1/odds across the legs, using netOdds where fees apply; below 1 for an arbitrage",
            "example": 0.9758
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/dto.ArbitrageLeg"
            }
          },
          "market": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "example": "Spread"
              },
              "hdp": {
                "type": "number",
                "description": "Line for Spread and Totals markets; omitted when the market has no line",
                "example": -1.5
              }
            }
          },
          "optimalStakes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/dto.OptimalStake"
            }
          },
          "profitMargin": {
            "type": "number",
            "description": "Margin at the quoted prices after exchange fees, as a percentage of totalStake (2.48 means 2.48%)",
            "example": 2.48
          },
          "totalStake": {
            "type": "number",
            "description": "1000, or less when a leg's maxStake caps the split; scale optimalStakes to your bankroll",
            "example": 1000
          },
          "updatedAt": {
            "type": "string",
            "description": "Last time the opportunity was confirmed",
            "example": "2026-10-20T18:42:11Z"
          }
        }
      },
      "dto.BookmakerOdds": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "awayDirectLink": {
            "type": "string"
          },
          "draw": {
            "type": "string"
          },
          "drawDirectLink": {
            "type": "string"
          },
          "hdp": {
            "type": "string"
          },
          "home": {
            "type": "string"
          },
          "homeDirectLink": {
            "type": "string"
          },
          "href": {
            "type": "string"
          }
        }
      },
      "dto.ClockDto": {
        "type": "object",
        "description": "Live match-clock state for in-play events. minute/playedSeconds are extrapolated server-side from the live feed and only advance while running is true.",
        "properties": {
          "minute": {
            "type": "integer",
            "example": 67,
            "description": "Current match minute"
          },
          "playedSeconds": {
            "type": "integer",
            "example": 4023,
            "description": "Seconds of play elapsed"
          },
          "period": {
            "type": "integer",
            "example": 2,
            "description": "Current period number"
          },
          "running": {
            "type": "boolean",
            "example": true,
            "description": "Whether the clock is currently running"
          },
          "statusDetail": {
            "type": "string",
            "example": "2nd half",
            "description": "Human-readable phase of play"
          },
          "serve": {
            "type": "string",
            "enum": [
              "home",
              "away"
            ],
            "description": "Current server (tennis, table tennis, volleyball)"
          },
          "injuryTime": {
            "type": "integer",
            "example": 4,
            "description": "Announced injury/stoppage time in minutes (football)"
          },
          "periodStartedAt": {
            "type": "integer",
            "example": 1792170000,
            "description": "Unix timestamp (seconds) when the current period started. Sent only when the feed has no played clock (for example ice hockey games with basic coverage), never alongside playedSeconds. Wall time, not game time: a stopped clock makes the elapsed wall time longer than the time played, so never treat it as playedSeconds. Omitted when the value is missing, in the future, or more than 3 hours old. Also present in WebSocket clock snapshots."
          }
        }
      },
      "dto.DroppingOddsEntry": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "integer",
            "example": 69455182
          },
          "event": {
            "$ref": "#/components/schemas/dto.DroppingOddsEvent"
          },
          "market": {
            "$ref": "#/components/schemas/dto.Market"
          },
          "betSide": {
            "type": "string",
            "enum": [
              "home",
              "away",
              "over",
              "under"
            ],
            "example": "home"
          },
          "odds": {
            "$ref": "#/components/schemas/dto.DroppingOddsMovement"
          },
          "lastMovedAt": {
            "type": "integer",
            "nullable": true,
            "description": "Unix milliseconds timestamp of last odds movement",
            "example": 1775851240182
          },
          "updatedAt": {
            "type": "integer",
            "description": "Unix milliseconds timestamp of last pipeline update",
            "example": 1775854172851
          }
        }
      },
      "dto.DroppingOddsEvent": {
        "type": "object",
        "properties": {
          "home": {
            "type": "string",
            "example": "Arsenal"
          },
          "away": {
            "type": "string",
            "example": "Bournemouth"
          },
          "date": {
            "type": "string",
            "description": "ISO 8601 date",
            "example": "2026-04-12T15:00:00.000Z"
          },
          "sport": {
            "$ref": "#/components/schemas/dto.Sport"
          },
          "league": {
            "$ref": "#/components/schemas/dto.League"
          }
        }
      },
      "dto.DroppingOddsMovement": {
        "type": "object",
        "properties": {
          "opening": {
            "type": "number",
            "description": "Opening odds value",
            "example": 2.05
          },
          "current": {
            "type": "number",
            "description": "Current odds value",
            "example": 1.52
          },
          "drop": {
            "$ref": "#/components/schemas/dto.OddsDrop"
          }
        }
      },
      "dto.EventInfo": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "home": {
            "type": "string"
          },
          "league": {
            "type": "string"
          },
          "sport": {
            "type": "string"
          }
        }
      },
      "dto.EventValueBet": {
        "type": "object",
        "properties": {
          "betSide": {
            "type": "string"
          },
          "bookmaker": {
            "type": "string"
          },
          "bookmakerOdds": {
            "$ref": "#/components/schemas/dto.BookmakerOdds"
          },
          "event": {
            "$ref": "#/components/schemas/dto.EventInfo"
          },
          "eventId": {
            "type": "integer"
          },
          "expectedValue": {
            "type": "number"
          },
          "expectedValueUpdatedAt": {
            "type": "string",
            "description": "Last time the expected value or the sharp limit increased. Not a freshness signal."
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When this value bet first appeared."
          },
          "bookmakerOddsUpdatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Last time this bookmaker price was written. May be absent."
          },
          "id": {
            "type": "string"
          },
          "market": {
            "$ref": "#/components/schemas/dto.MarketResult"
          }
        }
      },
      "dto.League": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          }
        }
      },
      "dto.Market": {
        "type": "object",
        "properties": {
          "hdp": {
            "type": "number"
          },
          "label": {
            "type": "string",
            "description": "Player name for player prop markets (e.g. \"Carlos Baleba\"). Only present on player prop entries."
          },
          "name": {
            "type": "string"
          }
        }
      },
      "dto.MarketResult": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "draw": {
            "type": "string"
          },
          "hdp": {
            "type": "number"
          },
          "home": {
            "type": "string"
          },
          "max": {
            "type": "number"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "dto.MultiMarketDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "odds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/dto.Odds"
            }
          },
          "updatedAt": {
            "type": "string"
          }
        }
      },
      "dto.Odds": {
        "type": "object",
        "properties": {
          "12": {
            "type": "string"
          },
          "1X": {
            "description": "Specialty market fields\nDouble Chance: 1X (home or draw), 12 (home or away), X2 (draw or away)",
            "type": "string"
          },
          "X2": {
            "type": "string"
          },
          "away": {
            "type": "string"
          },
          "awayLink": {
            "type": "string"
          },
          "depthAway": {
            "type": "string"
          },
          "depthDraw": {
            "type": "string"
          },
          "depthHome": {
            "type": "string"
          },
          "depthLayAway": {
            "type": "string"
          },
          "depthLayDraw": {
            "type": "string"
          },
          "depthLayHome": {
            "type": "string"
          },
          "depthLayNo": {
            "description": "Available liquidity to lay no. Yes/no markets only (currently Both Teams To Score on exchange-style books).",
            "type": "string"
          },
          "depthLayOver": {
            "description": "Available liquidity to lay over. On yes/no markets this repeats depthLayYes, kept for compatibility.",
            "type": "string"
          },
          "depthLayUnder": {
            "description": "Available liquidity to lay under. On yes/no markets this repeats depthLayNo, kept for compatibility.",
            "type": "string"
          },
          "depthLayYes": {
            "description": "Available liquidity to lay yes. Yes/no markets only (currently Both Teams To Score on exchange-style books).",
            "type": "string"
          },
          "depthNo": {
            "description": "Available liquidity to back no. Yes/no markets only (currently Both Teams To Score on exchange-style books).",
            "type": "string"
          },
          "depthOver": {
            "description": "Available liquidity to back over. On yes/no markets this repeats depthYes, kept for compatibility.",
            "type": "string"
          },
          "depthUnder": {
            "description": "Available liquidity to back under. On yes/no markets this repeats depthNo, kept for compatibility.",
            "type": "string"
          },
          "depthYes": {
            "description": "Available liquidity to back yes. Yes/no markets only (currently Both Teams To Score on exchange-style books).",
            "type": "string"
          },
          "draw": {
            "type": "string"
          },
          "drawLink": {
            "type": "string"
          },
          "even": {
            "type": "string"
          },
          "exactly": {
            "description": "Three-way corner lines only (Corners, Alternative Corners, 1st Half Corners): price for the count landing exactly on hdp. When present, Over and Under both lose on that number.",
            "type": "string"
          },
          "hdp": {
            "type": "number"
          },
          "home": {
            "type": "string"
          },
          "homeLink": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "layAway": {
            "type": "string"
          },
          "layDraw": {
            "type": "string"
          },
          "layHome": {
            "type": "string"
          },
          "layNo": {
            "type": "string"
          },
          "layOver": {
            "type": "string"
          },
          "layUnder": {
            "type": "string"
          },
          "layYes": {
            "type": "string"
          },
          "max": {
            "type": "integer"
          },
          "no": {
            "type": "string"
          },
          "none": {
            "description": "First Team To Score: none option",
            "type": "string"
          },
          "odd": {
            "description": "Odd/Even market",
            "type": "string"
          },
          "odds": {
            "description": "Labeled markets (Half Time / Full Time, Correct Score) - single odds value per outcome",
            "type": "string"
          },
          "over": {
            "type": "string"
          },
          "under": {
            "type": "string"
          },
          "yes": {
            "type": "string"
          }
        }
      },
      "dto.OddsDrop": {
        "type": "object",
        "properties": {
          "sinceOpening": {
            "type": "number",
            "description": "Percentage drop since opening",
            "example": 25.9
          },
          "12h": {
            "type": "number",
            "nullable": true,
            "description": "Percentage drop in last 12 hours",
            "example": 8.4
          },
          "24h": {
            "type": "number",
            "nullable": true,
            "description": "Percentage drop in last 24 hours",
            "example": 12.3
          },
          "48h": {
            "type": "number",
            "nullable": true,
            "description": "Percentage drop in last 48 hours",
            "example": null
          }
        }
      },
      "dto.OptimalStake": {
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": "string"
          },
          "potentialReturn": {
            "type": "number",
            "description": "Payout if this leg wins; the same for every leg up to rounding",
            "example": 1024.77
          },
          "side": {
            "type": "string"
          },
          "stake": {
            "type": "number",
            "example": 492.68
          }
        }
      },
      "dto.ParticipantDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "sport": {
            "description": "slug format (e.g., \"football\")",
            "type": "string"
          },
          "game": {
            "description": "Esports only: slug of the game this team plays (e.g. \"valorant\"). The same organisation has one participant per game.",
            "type": "string",
            "example": "valorant"
          },
          "shortCode": {
            "description": "Esports only: team short code, when known",
            "type": "string",
            "example": "G2"
          }
        }
      },
      "dto.PeriodScore": {
        "type": "object",
        "properties": {
          "away": {
            "type": "integer"
          },
          "home": {
            "type": "integer"
          },
          "overs": {
            "$ref": "#/components/schemas/dto.SideFloats",
            "description": "Cricket only. Overs bowled by each side in this innings."
          },
          "wickets": {
            "$ref": "#/components/schemas/dto.SideInts",
            "description": "Cricket only. Wickets lost by each side in this innings."
          }
        }
      },
      "dto.Score": {
        "type": "object",
        "properties": {
          "away": {
            "type": "integer"
          },
          "home": {
            "description": "Headline result: includes overtime, never a penalty shootout.",
            "type": "integer"
          },
          "periods": {
            "description": "Keyed p1..pN (that period only), ft, ot and ap (running totals after regulation, overtime and a penalty shootout), currentgame, mapN, inningN. See https://docs.odds-api.io/guides/live-events#period-scores",
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/dto.PeriodScore"
            }
          }
        }
      },
      "dto.SideFloats": {
        "type": "object",
        "description": "Home/away pair that can be fractional. Cricket overs use cricket notation: 19.3 means nineteen overs and three balls.",
        "properties": {
          "away": {
            "type": "number",
            "example": 20
          },
          "home": {
            "type": "number",
            "example": 20
          }
        }
      },
      "dto.SideInts": {
        "type": "object",
        "description": "Home/away pair of whole numbers (cricket wickets).",
        "properties": {
          "away": {
            "type": "integer",
            "example": 9
          },
          "home": {
            "type": "integer",
            "example": 6
          }
        }
      },
      "dto.SimpleEventDto": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "awayId": {
            "type": "integer"
          },
          "bookmakerCount": {
            "type": "integer"
          },
          "date": {
            "type": "string"
          },
          "home": {
            "type": "string"
          },
          "homeId": {
            "type": "integer"
          },
          "id": {
            "type": "integer"
          },
          "league": {
            "$ref": "#/components/schemas/dto.League"
          },
          "scores": {
            "$ref": "#/components/schemas/dto.Score"
          },
          "sport": {
            "$ref": "#/components/schemas/dto.Sport"
          },
          "status": {
            "type": "string"
          },
          "clock": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.ClockDto"
              }
            ],
            "description": "Live match clock (live events only; absent when no clock data is available)"
          },
          "esports": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.EsportsDto"
              }
            ],
            "description": "Esports events only: game, parent league, region and match format"
          }
        }
      },
      "dto.EsportsDto": {
        "type": "object",
        "description": "Present on esports events only",
        "properties": {
          "game": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.Sport"
              }
            ],
            "description": "The game being played, e.g. {\"name\": \"Valorant\", \"slug\": \"valorant\"}"
          },
          "league": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.League"
              }
            ],
            "description": "Parent league (VCT, LCK, LEC). Its slug stays the same across the league's splits and stages."
          },
          "region": {
            "description": "Region of the tournament: Western Europe, Eastern Europe, North America, South America, Asia, Oceania or Middle East. Omitted when unknown.",
            "type": "string",
            "example": "Western Europe"
          },
          "format": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.EsportsFormatDto"
              }
            ],
            "description": "Match format. Omitted when unknown."
          }
        }
      },
      "dto.EsportsFormatDto": {
        "type": "object",
        "properties": {
          "type": {
            "description": "bestOf or firstTo",
            "type": "string",
            "example": "bestOf"
          },
          "games": {
            "description": "Number of games: 3 for a best of 3",
            "type": "integer",
            "example": 3
          }
        }
      },
      "dto.Sport": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          }
        }
      },
      "models.Bookmaker": {
        "type": "object",
        "properties": {
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-08-01T09:00:00Z",
            "description": "When the bookmaker was added to the API, in UTC (RFC3339). Absent for a small number of legacy entries."
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded",
              "down"
            ],
            "example": "ok",
            "description": "Bookmaker status. `degraded`: no odds update on any of the book's matches for 60+ minutes. `down`: no update for 3+ hours while the book has 100+ active matches; its odds are then left out of every odds endpoint and removed over the WebSocket until it recovers. Books with fewer than 100 active matches are always `ok`."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "enum": [
              "maintenance",
              "unavailable",
              null
            ],
            "example": "maintenance",
            "description": "Why the status is not `ok`. Null when `ok`. `maintenance`: the bookmaker is temporarily offline on its side. `unavailable`: we temporarily have no fresh odds from this bookmaker."
          }
        }
      },
      "controllers.NativeIDMapping": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "integer",
            "example": 71515842,
            "description": "Our event id"
          },
          "home": {
            "type": "string",
            "example": "Pittsburgh Steelers",
            "description": "Home team of our event, in our orientation"
          },
          "away": {
            "type": "string",
            "example": "Cleveland Browns",
            "description": "Away team of our event, in our orientation"
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Start time of our event"
          },
          "sport": {
            "$ref": "#/components/schemas/controllers.Sport"
          },
          "league": {
            "$ref": "#/components/schemas/controllers.League"
          },
          "bookmaker": {
            "type": "string",
            "example": "Polymarket"
          },
          "market": {
            "type": "string",
            "example": "Spread",
            "description": "Market name, as in /v3/odds"
          },
          "label": {
            "type": "string",
            "description": "Selection label for labelled markets such as player props"
          },
          "hdp": {
            "type": "number",
            "example": -2.5,
            "description": "The line as /v3/odds shows it (the home handicap on a Spread). Omitted on markets without a line"
          },
          "side": {
            "type": "string",
            "example": "home",
            "enum": [
              "home",
              "away",
              "draw",
              "over",
              "under",
              "yes",
              "no"
            ]
          },
          "nativeEventId": {
            "type": "string",
            "example": "885112",
            "description": "The bookmaker's event id. For Polymarket it is the same value as `bookmakerIds` in `/v3/odds`. For Kalshi it is the event ticker the contract belongs to: the game ticker (the `bookmakerIds` value) for ML, and the spread or total event ticker for those contracts."
          },
          "marketId": {
            "type": "string",
            "example": "0x3b5c0c7e...",
            "description": "The bookmaker's market id (Polymarket conditionId, Kalshi contract ticker)"
          },
          "outcomeId": {
            "type": "string",
            "example": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
            "description": "The bookmaker's outcome id (Polymarket CLOB token id, Kalshi `yes` or `no`)"
          },
          "outcomeLabel": {
            "type": "string",
            "example": "Browns",
            "description": "The outcome's name at the bookmaker"
          },
          "extra": {
            "type": "object",
            "additionalProperties": {},
            "description": "Bookmaker-specific details, such as the Polymarket question"
          },
          "active": {
            "type": "boolean",
            "example": true,
            "description": "False once the bookmaker stopped listing the outcome"
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastCheckedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When we last saw the outcome at the bookmaker. Refreshed at least every 30 minutes while we track the event; Polymarket mappings stop refreshing at kickoff."
          }
        }
      },
      "controllers.NativeIDMappingPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.NativeIDMapping"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `cursor` to get the next page. `null` on the last page."
          }
        },
        "description": "Every /v3/mappings response. nextCursor is null for lookups and set in bulk sync while more pages remain."
      },
      "dto.FeedBookmakerStatusDoc": {
        "type": "object",
        "properties": {
          "lastWriteAt": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "live",
              "slow",
              "paused",
              "inactive",
              "unknown"
            ]
          }
        }
      },
      "controllers.EventSummary": {
        "type": "object",
        "properties": {
          "away": {
            "type": "string"
          },
          "computedAt": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "demo": {
            "type": "boolean"
          },
          "eventId": {
            "type": "string"
          },
          "home": {
            "type": "string"
          },
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.SummaryMarket"
            }
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "controllers.SummaryExchangeQuote": {
        "type": "object",
        "properties": {
          "best": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "liquidity": {
            "type": "number"
          },
          "venue": {
            "type": "string"
          }
        }
      },
      "controllers.SummaryExchanges": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/controllers.SummaryExchangeQuote"
        }
      },
      "controllers.SummaryLine": {
        "type": "object",
        "properties": {
          "books": {
            "type": "integer"
          },
          "exchanges": {
            "$ref": "#/components/schemas/controllers.SummaryExchanges"
          },
          "fairBooks": {
            "type": "integer"
          },
          "hdp": {
            "type": "number",
            "nullable": true
          },
          "main": {
            "type": "boolean"
          },
          "outcomes": {
            "$ref": "#/components/schemas/controllers.SummaryOutcomes"
          },
          "payout": {
            "$ref": "#/components/schemas/controllers.SummaryPayout"
          }
        }
      },
      "controllers.SummaryMarket": {
        "type": "object",
        "properties": {
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.SummaryLine"
            }
          },
          "name": {
            "type": "string"
          }
        }
      },
      "controllers.SummaryOutcome": {
        "type": "object",
        "properties": {
          "average": {
            "type": "number"
          },
          "best": {
            "type": "number"
          },
          "bestBookmakers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excluded": {
            "type": "integer"
          },
          "fair": {
            "type": "number"
          },
          "median": {
            "type": "number"
          },
          "sharpFair": {
            "type": "number"
          },
          "worst": {
            "type": "number"
          }
        }
      },
      "controllers.SummaryOutcomes": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/controllers.SummaryOutcome"
        }
      },
      "controllers.SummaryPayout": {
        "type": "object",
        "properties": {
          "average": {
            "type": "number"
          },
          "best": {
            "type": "number"
          }
        }
      },
      "controllers.SettlementResponse": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "integer",
            "example": 74919888
          },
          "sport": {
            "type": "string",
            "example": "Football"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "live",
              "awaiting_result",
              "settled",
              "cancelled"
            ],
            "example": "settled"
          },
          "final": {
            "type": "boolean",
            "description": "True when you can stop polling this event.",
            "example": true
          },
          "settledAt": {
            "type": "string",
            "format": "date-time",
            "description": "When we recorded the final state. Omitted when unknown.",
            "example": "2026-10-04T19:02:11Z"
          },
          "scores": {
            "allOf": [
              {
                "$ref": "#/components/schemas/dto.Score"
              }
            ],
            "description": "Present only for settled events with a usable score."
          }
        }
      },
      "controllers.SettlementsResponse": {
        "type": "object",
        "properties": {
          "settlements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/controllers.SettlementResponse"
            }
          },
          "notFound": {
            "type": "array",
            "description": "Event ids we have never seen.",
            "items": {
              "type": "string"
            },
            "example": [
              "999"
            ]
          }
        }
      },
      "controllers.GradeSelectionRequest": {
        "type": "object",
        "required": [
          "eventId",
          "market"
        ],
        "properties": {
          "ref": {
            "type": "string",
            "description": "Your own id for the bet, echoed back. At most 64 characters.",
            "example": "bet-1"
          },
          "eventId": {
            "description": "Event id, as a number or a numeric string.",
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "example": 74919888
          },
          "market": {
            "type": "string",
            "description": "Market name as served on /odds, for example ML, Spread, Totals HT, Corners Totals, Player Props.",
            "example": "Spread"
          },
          "side": {
            "type": "string",
            "description": "home, away, draw, over, under, yes, no, odd, even, 1x, 12, x2, none, or an HT/FT pair such as draw/home. Leave it out when the label carries the bet: correct scores, Winning Margin, goal counts, highest scoring half, Home/Away Team Exact Goals (or send that market's own team), and First/Last Match Corner when the label is 1 or 2. Correct Score and Set Betting also take the score itself as side (\"2-1\") instead of a label.",
            "example": "home"
          },
          "hdp": {
            "type": "number",
            "description": "The line as served on /odds. Handicaps are stated for the home side. Required on handicap, totals, corners, bookings and player prop markets.",
            "example": -0.25
          },
          "label": {
            "type": "string",
            "description": "Row label as served. Required for Player Props (\"Arike Ogunbowale (Assists)\") and labelled markets: Home/Away Team Exact Goals (\"Arsenal - 2 Goals\"), Correct Score (\"2-1\"), Winning Margin (\"2 (1)\"), goal counts (\"3+ Goals\") and Highest Scoring Half (\"2nd Half\"). First/Last Match Corner also take \"1\" or \"2\".",
            "example": "Arike Ogunbowale (Assists)"
          },
          "tieRule": {
            "type": "string",
            "enum": [
              "lose",
              "void"
            ],
            "description": "What a level score does to a moneyline bet in sports where books differ. Ignored where a fixed rule applies."
          }
        }
      },
      "controllers.GradeRequest": {
        "type": "object",
        "required": [
          "selections"
        ],
        "properties": {
          "selections": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/controllers.GradeSelectionRequest"
            }
          }
        }
      },
      "settlement.Basis": {
        "type": "object",
        "description": "The score the verdict was computed from. Only on graded score markets.",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "regulation",
              "full_game",
              "match_result",
              "first_half",
              "second_half",
              "first_period",
              "period_2",
              "period_3",
              "period_4",
              "period_5",
              "games",
              "map_1",
              "map_2",
              "map_3",
              "map_4",
              "map_5"
            ],
            "example": "regulation"
          },
          "home": {
            "type": "integer",
            "example": 3
          },
          "away": {
            "type": "integer",
            "example": 2
          }
        }
      },
      "controllers.GradeResponse": {
        "type": "object",
        "properties": {
          "ref": {
            "type": "string",
            "example": "bet-1"
          },
          "eventId": {
            "type": "integer",
            "example": 74919888
          },
          "result": {
            "type": "string",
            "enum": [
              "won",
              "lost",
              "void",
              "half_won",
              "half_lost",
              "pending",
              "ungradeable"
            ],
            "example": "won"
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "description": "Null for won, lost, half_won and half_lost. Always set otherwise.",
            "enum": [
              "push",
              "event_cancelled",
              "event_not_started",
              "event_live",
              "awaiting_result",
              "awaiting_stats",
              "event_not_found",
              "unsupported_market",
              "invalid_side",
              "invalid_line",
              "invalid_label",
              "incomplete_score",
              "ambiguous_tie",
              "player_not_matched",
              "stats_unavailable",
              "result_unavailable",
              null
            ],
            "example": null
          },
          "final": {
            "type": "boolean",
            "description": "True when you can stop polling this selection.",
            "example": true
          },
          "basis": {
            "$ref": "#/components/schemas/settlement.Basis"
          }
        }
      },
      "controllers.GradesResponse": {
        "type": "object",
        "properties": {
          "grades": {
            "type": "array",
            "description": "One grade per selection, in the order sent.",
            "items": {
              "$ref": "#/components/schemas/controllers.GradeResponse"
            }
          }
        }
      }
    }
  }
}
