{"openapi":"3.1.0","info":{"title":"odds-api","description":"The Odds API V1 provides sports and racing events, bookmaker odds, exchange and prediction-market order books,\nlive price updates, betting opportunity snapshots, and result lookups for production integrations.\n\nAuthenticate every request with `X-API-Key: <your_api_key>` unless an endpoint explicitly states it is public.\nUse `https://api.odds-api.net/v1` as the production base URL.\n\nSnapshot endpoints return JSON and include timestamps or resume tokens when live updates are available.\n`/stream` endpoints use Server-Sent Events (`text/event-stream`) and `/ws` endpoints use WebSockets. Stream\nmessages use the same shape in both transports: an event name such as `delta`, `heartbeat`, or `resync`, plus a\nJSON payload. Store the latest `resume` value and pass it back as `since` after reconnecting. A `heartbeat` message\n(`event: heartbeat` with a JSON `data` payload on SSE) is sent whenever `heartbeat_sec` passes without any other\nmessage, including while updates for bookmakers or markets outside your filters are flowing; treat a gap longer than\n`heartbeat_sec` plus a margin as a dead connection and reconnect.\n\nEvery V1 HTTP response carries an `X-Request-ID` header (WebSocket handshakes too). Send your own `X-Request-ID`\n(1-128 characters: letters, digits, `.`, `_`, `:` or `-`) to correlate requests, otherwise one is generated; quote it\nwhen contacting support. When a `bookmakers` filter names bookmakers your API key cannot access, or keys that are\nnot bookmakers, the response says so instead of silently dropping them: `X-Excluded-Bookmakers: key:reason,...`\non event-odds and odds-history responses, `excluded_bookmakers` on odds snapshots, and `excluded_bookmakers` in\nthe opening WebSocket heartbeat and in event-odds heartbeats. Reasons are `not_entitled`\nand `unknown_bookmaker`. Very stale prices are left out by default: a bookmaker last accepted more than\nmax(24 h, 20 x `target_refresh_interval_seconds`) ago, or holding only pre-match prices more than 10 minutes after\nkickoff, is omitted from odds snapshots and main lines and listed in `excluded_bookmakers` with reason `stale`\n(`detail` `age` or `started`, plus `as_of_ts_ms`). Pass `include_stale=true` to receive those prices anyway. WebSocket event-odds heartbeats also carry `resume`; on SSE persist `resume` from deltas.\n\nProduction clients should start with catalog discovery, page event lists with `limit` and `cursor`, fetch odds\nsnapshots for initial state, then use streams for hot events. Recommended starting polling intervals are:\ncatalog metadata every 6-24 hours, sports event lists every 5-15 minutes, racing event lists every 1-5 minutes,\nodds snapshots every 60-120 seconds when streams are not used, betting opportunity snapshots every 30-120 seconds,\nand results every 1-5 minutes after the event starts until settled.\n\nHandle HTTP 429 by honoring `Retry-After` when present, otherwise use jittered exponential backoff. Use\n`/usage` to detect monthly API-credit quota exhaustion and `/limits` to discover response, stream, add-on, and\nplan caps. Most standard API calls use 1 credit; large odds snapshots, history, broad aggregate feeds, and\nsupport-approved betting feeds may use multiple credits as weighted metering rolls out. Cache snapshots by request\nshape and respect `ttl_seconds` when present. `as_of_ts_ms` is an event-wide clock: an accepted update from any\nbookmaker on the event renews it, including bookmakers your request filtered out, so never use it to judge a\nspecific bookmaker. For per-bookmaker freshness use `bookmaker_as_of_ts_ms` (with `oldest_bookmaker_as_of_ts_ms`,\n`newest_bookmaker_as_of_ts_ms` and `stale_bookmakers` summarising the returned bookmakers).\n`target_refresh_interval_seconds` is a scheduling target, not an\nartificial plan delay or a guarantee that an upstream bookmaker answered on time. Keep the most recent `resume` token with\ncached state. On stream disconnect, reconnect with `since=<last_resume>` and `catchup=true`; on `resync`, reload\nthe snapshot before applying more deltas.\n\nOdds can change quickly. Check event and bookmaker freshness timestamps, handle empty arrays, suspended selections, rate limits, and stale\nprices before displaying or acting on any betting data.\n\nNew odds-api.net API keys default to a compact response shape that keeps essential IDs, prices, teams, markets,\ntimestamps, and resume tokens while omitting raw payloads, source metadata, internal/debug IDs, bookmaker links,\nand non-offered price columns. Existing API keys keep the historical full response shape unless they explicitly\npass the compacting query flags. There is no public `profile` parameter; use the documented per-field flags when\nyou need to opt a compact client back into a specific field group.","version":"1.0.0","license":{"name":"Proprietary","url":"https://odds-api.net"},"x-workflow-examples":[{"name":"positive_ev_request","summary":"Find positive EV bets for a league.","steps":["GET /v1/events?sport=rugby-league&league=NRL","GET /v1/bets/snapshot?strategies=pos_ev","Use response timestamps and stake/risk controls before showing user-facing picks."]},{"name":"arbitrage_request","summary":"Find arbitrage opportunities across allowed bookmakers.","steps":["GET /v1/bookmakers","GET /v1/bets/snapshot?strategies=arbitrage","Show execution-risk caveats; never present arbitrage as guaranteed after limits, voids, or delays."]},{"name":"odds_history_request","summary":"Get line movement for a market.","steps":["GET /v1/events/{event_id}/odds/snapshot","Pick a selection_key from an odds line.","GET /v1/events/{event_id}/odds/history?selection_key=..."]},{"name":"prediction_market_orderbook_request","summary":"Read and follow a curated prediction-market order book.","steps":["GET /v1/events?sport=basketball&league=NBA","GET /v1/events/{event_id}/prediction-markets/orderbook/snapshot?providers=polymarket,kalshi&depth=3","Connect to the matching /stream or /ws route with since=<snapshot resume>."]}],"x-responsible-gambling":"Do not present betting outcomes as risk-free. Always mention execution risk, stale prices, bookmaker limits, voids, delays, and jurisdictional availability in user-facing products.","x-production-integration":{"recommended_flow":["Authenticate backend requests with X-API-Key.","Discover sports, leagues, and bookmakers before storing local filters.","Page sports or racing events with limit and cursor.","Fetch odds snapshots for initial state. Explicit bookmaker filters are complete in one response; otherwise follow bookmaker-complete pages until complete=true. Persist as_of_ts_ms, ttl_seconds, and resume.","Use SSE or WebSocket streams for realtime updates and reconnect with since=<last_resume>.","Use history endpoints for line movement and results endpoints after events finish."],"recommended_polling_intervals":{"catalog_metadata":"6-24h","sports_events":"5-15m, or 1-5m for active leagues and near-start windows","racing_events":"1-5m with narrow time windows","odds_snapshots_without_streams":"60-120s, or 15-30s for priority events with strict quota controls","betting_opportunity_snapshots":"30-120s depending on alert urgency","results_after_start":"1-5m until settled, then back off"},"stream_reconnects":["Snapshot first, then connect to /stream or /ws with matching filters.","Apply delta messages idempotently and persist the newest resume token.","Use heartbeat messages as liveness checks.","Reconnect with jittered exponential backoff and since=<last_resume>.","Reload the snapshot when a resync message indicates the resume token is unavailable."],"rate_limit_backoff":["Honor Retry-After on 429 when present.","Otherwise start around 2 seconds and double up to about 60 seconds with jitter.","Use X-RateLimit-* response headers when present to tune callers.","Use /usage to detect monthly API-credit quota exhaustion and stop retry loops."],"cache_strategy":["Cache by endpoint path, event ID, normalized filters, page cursor, and product context.","Respect ttl_seconds when present and always surface as_of_ts_ms.","Use streams to update hot caches and reload snapshots after resync or parse failure.","Prefer stale-while-revalidate displays with a visible timestamp."],"failure_modes":["400 invalid request shape, cursor, timestamp, or filter.","401 missing or invalid API key.","403 key lacks plan, product, bookmaker, stream, racing, or strategy access.","404 event, race, result, or selection is unavailable.","429 rate limit or monthly quota exhaustion.","5xx transient service failure; retry with backoff and keep last good cached data marked stale.","Stream close or resync; reconnect with since or reload the snapshot."]}},"paths":{"/":{"get":{"tags":["Start here"],"summary":"Start here: API metadata","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiRootResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the API name, version, OpenAPI document URL, and hosted reference URL.","security":[],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/status":{"get":{"tags":["Status"],"summary":"API status: Public health summary","operationId":"public_status_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicStatusResponse"},"examples":{"default":{"summary":"API status: Public health summary","value":{"status":"operational","as_of":"2026-04-29T10:25:00Z","window_seconds":300,"components":[{"id":"rest_api","name":"REST API","status":"operational","metrics":{"uptime_pct":100.0,"p50_ms":24.0,"p95_ms":410.0,"p99_ms":846.0,"error_rate_pct":0.02}}],"rate_limits":{"status":"operational","throttled_pct":0.4},"source":{"fresh":true,"age_seconds":18}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns a sanitized public status summary for buyer-facing pages. The response includes recent component availability, latency percentiles, 5xx error rate, stream health, and rate-limit health without exposing internal service names, infrastructure metrics, bookmaker details, raw traffic volume, or incident history.","security":[],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/me":{"get":{"tags":["Account"],"summary":"Account: Current identity","operationId":"me_me_get","security":[{"ApiKeyAuth":[]}],"parameters":[],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIdentityResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the authenticated API identity and enabled product capabilities for the supplied key.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/usage":{"get":{"tags":["Account"],"summary":"Account: Usage","operationId":"usage_usage_get","security":[{"ApiKeyAuth":[]}],"parameters":[],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"},"examples":{"default":{"summary":"Account: Usage","value":{"period_start_utc":"2026-05-01T00:00:00Z","period_end_utc":"2026-06-01T00:00:00Z","plan":"live","pricing_model":"odds_api_net_v2","api_credits_used":18420,"api_credits_limit":20000000,"stream_hours_used":438.25,"stream_hours_limit":6000,"stream_logical_bytes_used":187654321,"stream_logical_bytes_limit":536870912000,"stream_concurrent_units_used":7,"stream_concurrent_units_limit":25,"exceeded":false}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns quota and usage counters for the supplied API key. New odds-api.net pricing uses API credits rather than raw request counts. Production clients should check this endpoint when 429 responses persist so quota exhaustion does not become an infinite retry loop.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/limits":{"get":{"tags":["Account"],"summary":"Account: Limits","operationId":"limits_limits_get","security":[{"ApiKeyAuth":[]}],"parameters":[],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LimitsResponse"},"examples":{"default":{"summary":"Account: Limits","value":{"responses":{"events_limit_max":1000,"odds_snapshot_limit_max":25000,"bets_snapshot_limit_max":20000},"sse":{"heartbeat_sec_min":5,"heartbeat_sec_max":120,"max_batch_default":500},"streams":{"metering":"all authenticated API-key SSE and WebSocket connections","formula":"stream_units * open_seconds / 3600","enforcement_interval_seconds":5}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns contract-level API-credit, request, stream, add-on, and response limits that clients should respect. Use this to cap page sizes, snapshot sizes, stream heartbeat settings, and stream batch sizes before starting high-volume jobs.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/sports":{"get":{"tags":["Catalog"],"summary":"Catalog: Sports","operationId":"sports_sports_get","security":[{"ApiKeyAuth":[]}],"parameters":[],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StringListResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Lists sports with event and odds coverage.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/leagues":{"get":{"tags":["Catalog"],"summary":"Catalog: Leagues","operationId":"leagues_leagues_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"description":"Sport filter. Use `/sports` to discover supported values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueListResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Lists available leagues. Pass `sport` to narrow the response.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/bookmakers":{"get":{"tags":["Catalog"],"summary":"Catalog: Bookmakers","operationId":"bookmakers_bookmakers_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional comma-separated country code filter, for example `AU` or `AU,UK`.","title":"Country Code"},"description":"Comma-separated country code filter, for example `AU` or `AU,UK`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookmakerCatalogResponse"},"examples":{"default":{"summary":"Catalog: Bookmakers","value":{"items":[{"bookmaker":"bet365","country_codes":["AU","UK"]},{"bookmaker":"pinnacle","country_codes":["US"]}]}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Lists active bookmakers accepted by bookmaker filters across odds and betting endpoints. Each item includes the country codes where that bookmaker is available. Pass `country_code=AU` or `country_code=AU,UK` to filter the catalog.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/bookmakers/countries":{"get":{"tags":["Catalog"],"summary":"Catalog: Bookmaker countries","operationId":"bookmaker_countries_bookmakers_countries_get","security":[{"ApiKeyAuth":[]}],"parameters":[],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookmakerCountriesCatalogResponse"},"examples":{"default":{"summary":"Catalog: Bookmaker countries","value":{"items":[{"country_code":"AU","country":"Australia","bookmakers":["bet365","sportsbet"]},{"country_code":"UK","country":"United Kingdom","bookmakers":["bet365"]}]}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Lists country codes represented in the active bookmaker catalog and the bookmakers available in each country.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/coverage":{"get":{"tags":["Catalog"],"summary":"Catalog: Coverage","operationId":"coverage_coverage_get","security":[],"parameters":[{"name":"bookmaker","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Canonical bookmaker filter, for example `bet365`.","title":"Bookmaker"},"description":"Canonical bookmaker filter. Use `/bookmakers` or `/coverage` to discover supported keys."},{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sport filter, for example `basketball`.","title":"Sport"},"description":"Sport filter. Use `/sports` to discover supported values."},{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"League filter, for example `NBA`.","title":"League"},"description":"League filter. Use `/leagues?sport=...` to discover supported values."},{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional comma-separated country code filter.","title":"Country Code"},"description":"Comma-separated country code filter, for example `AU` or `AU,UK`."},{"name":"lookback_days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Lookback Days"},"description":"Number of days of recently observed approximate market coverage to include. Maximum is 90."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageResponse"},"examples":{"default":{"summary":"Catalog: Coverage","value":{"as_of":"2026-04-29T10:25:00Z","bookmakers":[{"bookmaker":"bet365","country_codes":["AU","UK"]},{"bookmaker":"sportsbet","country_codes":["AU"]}],"sports":["basketball","rugby league"],"leagues":[{"sport":"basketball","league":"NBA"},{"sport":"rugby league","league":"NRL"}],"markets":[{"bookmaker":"bet365","sport":"basketball","league":"NBA","bet_type":"moneyline","last_seen_at":"2026-04-29T10:20:00Z","sample_event_id":"3704597661"},{"bookmaker":"sportsbet","sport":"rugby league","league":"NRL","bet_type":"total","metric":"tries","last_seen_at":"2026-04-29T10:18:00Z","sample_event_id":"3704597662"}],"source":{"markets_are_approximate":true,"lookback_days":30}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns public bookmaker, sport, league, and recently observed market coverage. Market records are approximate and based on normalized odds lines seen in the configured lookback window, not a guarantee that every market is available for every event at request time.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/widgets/odds-ticker":{"get":{"tags":["Widgets"],"summary":"Widgets: Odds ticker","operationId":"odds_ticker_widgets_odds_ticker_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"League"},"description":"League filter. Use `/leagues?sport=...` to discover supported values."},{"name":"bookmakers","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys."},{"name":"widget_id","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_.:-]+$","title":"Widget Id"},"description":"Stable widget identifier configured on the API client record."},{"name":"markets","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markets"},"description":"Comma-separated widget market list. Supported values are moneyline, handicap, and total; aliases include h2h, 1x2, spread, and over_under."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"window_hours","in":"query","required":false,"schema":{"type":"integer","maximum":168,"minimum":1,"default":48,"title":"Window Hours"}},{"name":"event_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":256},{"type":"null"}],"title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"include_completed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Completed"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WidgetOddsTickerResponse"},"examples":{"default":{"summary":"Widgets: Odds ticker","value":{"league":"EPL","widget_id":"homepage-ticker","last_updated":"2026-07-09T01:02:03Z","events":[{"league":"EPL","event_name":"Arsenal vs Chelsea","start_time":1783558800,"last_updated":"2026-07-09T01:02:03Z","markets":[{"market":"moneyline 3w","bookmakers":[{"label":"tab","selections":[{"selection":"home","price":2.2},{"selection":"away","price":2.9},{"selection":"draw","price":3.4}]}]}]}]}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns a small public-safe odds ticker payload for an embeddable website widget. The response is projected from the same Redis-backed main-line sports odds used by the API. Rolling league requests return upcoming events. An exact `event_id` returns current odds; `include_completed=true` also permits display of a confirmed finished event's retained final usable capture. Exact-event responses add event identity, lifecycle and capture metadata. Missing captures return an explicit empty result. Cancelled/postponed events do not return archived prices. This grants no general odds-history access. The payload omits raw payloads, private source metadata, links, no-vig prices, fair odds, debug IDs, and team logo metadata. API keys marked `widgets_only=true` can access this route plus account routes only.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events":{"get":{"tags":["Sports events"],"summary":"Sports events: Search","operationId":"list_events_events_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"description":"Sport filter. Use `/sports` to discover supported values."},{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League"},"description":"League filter. Use `/leagues?sport=...` to discover supported values."},{"name":"start_from","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Unix seconds; default now.","title":"Start From"},"description":"Unix seconds lower bound for event start time. Use bounded windows in production polling."},{"name":"start_to","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Unix seconds; optional.","title":"Start To"},"description":"Unix seconds upper bound for event start time. Keep windows narrow for hot sync jobs."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pagination cursor: 'start_time:event_id'.","title":"Cursor"},"description":"Pagination cursor from the previous `next_cursor`. Keep filters identical between pages."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"include_bookmaker_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Bookmaker Ids"},"description":"When true, include bookmaker-to-odds-data IDs and preview ID maps on event responses."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_opportunity_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Opportunity Counts"}},{"name":"not_started_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Not Started Only"}},{"name":"not_started_buffer_seconds","in":"query","required":false,"schema":{"type":"integer","default":120,"title":"Not Started Buffer Seconds"}},{"name":"event_states","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Lifecycle filter. Requesting in_play automatically applies the live lookback window.","title":"Event States"},"description":"Lifecycle filter. Requesting in_play automatically applies the live lookback window."},{"name":"live_candidates","in":"query","required":false,"schema":{"type":"boolean","description":"Include already-started events that remain candidates for live play; this is not confirmation of current play.","default":false,"title":"Live Candidates"},"description":"Include already-started events that remain candidates for live play; this is not confirmation of current play."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventListResponse"},"examples":{"default":{"summary":"Sports events: Search","value":{"items":[{"event_id":"3704597661","sport":"rugby-league","league":"NRL","start_time":1760000000,"home_team":"Home","away_team":"Away","bookmakers":{"bet365":"odds-doc-id"}}],"next_cursor":null,"count":1}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Searches sports events by sport, league, team, time window, status, bookmaker coverage, and pagination cursor. For production polling, use bounded time windows, keep filters stable across pages, and pass `next_cursor` back as `cursor` until there is no next cursor. For live discovery start with `/v1/events/live`; `event_states=in_play` returns only events with a fresh live observation and adds a `hint` when started but unconfirmed events were excluded. Every item has a plain `live_status`.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/live":{"get":{"tags":["Sports events"],"summary":"GET events live","description":"Public Odds API operation. Authenticate with `X-API-Key`. Check timestamps before displaying prices and handle empty, stale, or suspended markets.","operationId":"list_live_event_candidates_events_live_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"description":"Sport filter. Use `/sports` to discover supported values."},{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League"},"description":"League filter. Use `/leagues?sport=...` to discover supported values."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pagination cursor: 'start_time:event_id'.","title":"Cursor"},"description":"Pagination cursor from the previous `next_cursor`. Keep filters identical between pages."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"include_bookmaker_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Bookmaker Ids"},"description":"When true, include bookmaker-to-odds-data IDs and preview ID maps on event responses."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_opportunity_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Opportunity Counts"}},{"name":"confirmed","in":"query","required":false,"schema":{"type":"boolean","description":"Only events with a fresh live observation (live_status=live); same as /v1/events?event_states=in_play.","default":false,"title":"Confirmed"},"description":"Only events with a fresh live observation (live_status=live); same as /v1/events?event_states=in_play."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventListResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}":{"get":{"tags":["Sports events"],"summary":"Sports events: Event details","operationId":"get_event_events__event_id__get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_bookmaker_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Bookmaker Ids"},"description":"When true, include bookmaker-to-odds-data IDs and preview ID maps on event responses."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetail"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the current event record for a canonical sports event ID.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/bookmakers":{"get":{"tags":["Sports events"],"summary":"Sports events: Bookmaker coverage","operationId":"event_bookmakers_events__event_id__bookmakers_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookmakersResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Lists bookmakers currently attached to a sports event.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/fair-odds":{"get":{"tags":["Sports odds"],"summary":"Fair odds: Snapshot","description":"Public Odds API operation. Authenticate with `X-API-Key`. Check timestamps before displaying prices and handle empty, stale, or suspended markets.","operationId":"fair_odds_events__event_id__fair_odds_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"selection_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Selection Id"}},{"name":"selection_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Selection Key"},"description":"Stable selection identifier from an odds snapshot line, used for history and line movement."},{"name":"market_group_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Market Group Id"},"description":"Optional market grouping filter for history queries."},{"name":"bet_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Bet Type"}},{"name":"metric","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Metric"}},{"name":"period","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Period"}},{"name":"period_str","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Period Str"}},{"name":"line","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Line"}},{"name":"player_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Player Name"}},{"name":"team_subject","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Team Subject"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Cursor"},"description":"Pagination cursor from the previous `next_cursor`. Keep filters identical between pages."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FairPricesResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/odds/snapshot":{"get":{"tags":["Sports odds"],"summary":"Event odds: Snapshot","operationId":"odds_snapshot_events__event_id__odds_snapshot_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":25000,"minimum":1,"description":"Soft item target when bookmakers is omitted. Pages contain whole bookmakers and may exceed this target. When bookmakers is supplied, all matching lines are returned up to the response safety cap.","default":2000,"title":"Limit"},"description":"Soft item target when `bookmakers` is omitted. Pages contain whole bookmakers and may exceed this target. With an explicit bookmaker filter, all matching lines are returned up to the 25,000-item safety cap."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque bookmaker-page cursor from next_cursor. Use only when bookmakers is omitted and keep all filters identical between pages.","title":"Cursor"},"description":"Opaque bookmaker-page cursor from the previous `next_cursor`. Use only when `bookmakers` is omitted and keep all filters identical between pages."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list. Explicitly requested bookmakers are returned complete in one response, up to the response safety cap.","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Explicitly requested bookmakers are returned complete in one response, up to the 25,000-item safety cap. Use `/bookmakers` to discover supported keys. Requested keys this API key cannot access, or that are not bookmakers, are listed in `excluded_bookmakers` and the `X-Excluded-Bookmakers` header."},{"name":"types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated type allow-list","title":"Types"},"description":"Comma-separated market type allow-list for odds filters."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"periods","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated periods allow-list","title":"Periods"},"description":"Comma-separated period allow-list for odds filters. Each value matches a line's numeric `period` or its period label, for example `full time`, `1st half` or `after 15 minutes`. Numeric `0` also matches timed checkpoints such as `after 15 minutes`; use `full time` to select only full-time lines."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"include_stale","in":"query","required":false,"schema":{"type":"boolean","description":"Return bookmakers whose prices are very stale (last accepted more than max(24 h, 20 x target_refresh_interval_seconds) ago, or only pre-match prices after kickoff). By default they are left out and listed in excluded_bookmakers with reason `stale`.","default":false,"title":"Include Stale"},"description":"Return bookmakers whose prices are very stale (last accepted more than max(24 h, 20 x target_refresh_interval_seconds) ago, or only pre-match prices after kickoff). By default they are left out and listed in excluded_bookmakers with reason `stale`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OddsSnapshotResponse"},"examples":{"default":{"summary":"Event odds: Snapshot","value":{"event_id":"3704597661","as_of_ts_ms":1760000000000,"snapshot_capture_ts_ms":1759999999800,"bookmaker_as_of_ts_ms":{"bet365":1760000000000},"oldest_bookmaker_as_of_ts_ms":1760000000000,"newest_bookmaker_as_of_ts_ms":1760000000000,"stale_bookmakers":[],"target_refresh_interval_seconds":60,"ttl_seconds":1800,"items":[{"id":"bet365::moneyline::moneyline::0::::home::","event_id":"3704597661","bookmaker":"bet365","market_key":"moneyline","bet_type":"moneyline","period":"full time","side":"home","selection_name":"Home","odds":2.1,"fair_odds":1.98,"is_available":true}],"next_cursor":null,"complete":true,"bookmakers_included":["bet365"],"bookmaker_counts":{"bet365":1},"resume":"1760000000000-0"}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}},"X-Excluded-Bookmakers":{"description":"Present when the `bookmakers` filter named bookmakers this response cannot contain: comma-separated `key:reason` pairs, where reason is `not_entitled` (not included in this API key's plan or bookmaker grant) or `unknown_bookmaker` (not a key from `/bookmakers`).","schema":{"type":"string","example":"williamhill:not_entitled,bet356:unknown_bookmaker"}}}},"413":{"description":"The requested bookmaker-complete snapshot exceeds the response safety cap.","headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the current odds lines for one event. Use filters to narrow bookmakers, market types, market keys, and periods. An explicit `bookmakers` filter returns every matching line for those bookmakers in one response, up to the 25,000-item safety cap. Without a bookmaker filter, pages contain whole bookmakers, so a bookmaker's matching markets are never split across pages. Follow the opaque `next_cursor` until `complete=true`. Cache by request shape. `as_of_ts_ms` is event-wide: the latest acceptance from any bookmaker on the event, including bookmakers this response does not return, so it can look fresh while the bookmakers you asked for are old. Use `bookmaker_as_of_ts_ms` for bookmaker-specific freshness and compare it with `target_refresh_interval_seconds`; `oldest_bookmaker_as_of_ts_ms`, `newest_bookmaker_as_of_ts_ms` and `stale_bookmakers` (returned bookmakers last accepted more than twice the target interval ago) summarise it (prediction markets report when their current contract prices were accepted). Respect `ttl_seconds` when present, and persist `resume` when you plan to subscribe to updates. Pass `price_fields=odds,fair` to include nullable composite fair odds alongside bookmaker odds. Exchange orderbooks are excluded from this sportsbook-style odds surface.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/odds/stream":{"get":{"tags":["Sports odds"],"summary":"Event odds: Stream (SSE)","operationId":"odds_stream_events__event_id__odds_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys. Requested keys this API key cannot access, or that are not bookmakers, are reported in the `X-Excluded-Bookmakers` header."},{"name":"types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated type allow-list","title":"Types"},"description":"Comma-separated market type allow-list for odds filters."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"periods","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated periods allow-list","title":"Periods"},"description":"Comma-separated period allow-list for odds filters. Each value matches a line's numeric `period` or its period label, for example `full time`, `1st half` or `after 15 minutes`. Numeric `0` also matches timed checkpoints such as `after 15 minutes`; use `full time` to select only full-time lines."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","snapshot_id":"capture-123:3704597661","batch_index":1,"batch_count":1,"changes":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}},"X-Excluded-Bookmakers":{"description":"Present when the `bookmakers` filter named bookmakers this response cannot contain: comma-separated `key:reason` pairs, where reason is `not_entitled` (not included in this API key's plan or bookmaker grant) or `unknown_bookmaker` (not a key from `/bookmakers`).","schema":{"type":"string","example":"williamhill:not_entitled,bet356:unknown_bookmaker"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for odds changes on one event. Subscribe after reading the snapshot and pass the snapshot `resume` value as `since` to receive catch-up changes when available. Handle ordered semantic `delta` batches idempotently and persist each batch's `resume`; a `heartbeat` carries current freshness even when prices did not change. Reload the snapshot after `resync`. Exchange orderbook changes are served only from the exchange orderbook stream.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/odds/ws":{"get":{"operationId":"websocket_events_event_id_odds_ws","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys."},{"name":"types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated type allow-list","title":"Types"},"description":"Comma-separated market type allow-list for odds filters."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"periods","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated periods allow-list","title":"Periods"},"description":"Comma-separated period allow-list for odds filters. Each value matches a line's numeric `period` or its period label, for example `full time`, `1st half` or `after 15 minutes`. Numeric `0` also matches timed checkpoints such as `after 15 minutes`; use `full time` to select only full-time lines."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","snapshot_id":"capture-123:3704597661","batch_index":1,"batch_count":1,"changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","snapshot_id":"capture-123:3704597661","batch_index":1,"batch_count":1,"changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/events/{event_id}/odds/stream","tags":["Sports odds"],"summary":"Event odds: Stream (WebSocket)","description":"WebSocket feed for odds changes on one event. Messages use the same `delta`, `heartbeat`, and `resync` payloads as the SSE stream. Reconnect with jittered exponential backoff and `since=<last_resume>`.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/odds/history":{"get":{"tags":["Sports odds"],"summary":"Event odds history: Snapshot","operationId":"odds_history_events__event_id__odds_history_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"selection_key","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Selection Key"},"description":"Stable selection identifier from an odds snapshot line, used for history and line movement."},{"name":"market_group_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Group Id"},"description":"Optional market grouping filter for history queries."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys. Requested keys this API key cannot access, or that are not bookmakers, are reported in the `X-Excluded-Bookmakers` header."},{"name":"from_ts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO8601 UTC start","title":"From Ts"},"description":"ISO8601 UTC start timestamp for a bounded history query."},{"name":"to_ts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO8601 UTC end","title":"To Ts"},"description":"ISO8601 UTC end timestamp for a bounded history query."},{"name":"price_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(odds|odds_no_vig|fair_odds)$","default":"odds","title":"Price Type"},"description":"History price type to return, for example odds."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"limit_points_per_bookmaker","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":2000,"title":"Limit Points Per Bookmaker"},"description":"Maximum history points per bookmaker. Use this to keep chart/backtest payloads bounded."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OddsHistoryResponse"},"examples":{"default":{"summary":"Event odds history: Snapshot","value":{"event_id":"3704597661","selection_key":"moneyline:home","price_type":"odds","series":[{"bookmaker_name":"bet365","points":[{"tick_ts":"2026-04-29T08:00:00Z","is_available":true,"odds":2.08},{"tick_ts":"2026-04-29T08:05:00Z","is_available":true,"odds":2.1}]}],"meta":{"from_ts":"2026-04-29T08:00:00Z","to_ts":"2026-04-29T09:00:00Z","available_price_types":["odds","odds_no_vig","fair_odds"]}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}},"X-Excluded-Bookmakers":{"description":"Present when the `bookmakers` filter named bookmakers this response cannot contain: comma-separated `key:reason` pairs, where reason is `not_entitled` (not included in this API key's plan or bookmaker grant) or `unknown_bookmaker` (not a key from `/bookmakers`).","schema":{"type":"string","example":"williamhill:not_entitled,bet356:unknown_bookmaker"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns line movement for a single selection across bookmakers and a time range. Use `selection_key` from an odds snapshot response, bound queries with `from_ts` and `to_ts`, and narrow by bookmaker or market when building charts or backtests.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/odds/history/stream":{"get":{"tags":["Sports odds"],"summary":"Event odds history: Stream (SSE)","operationId":"odds_history_stream_events__event_id__odds_history_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"selection_key","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Selection Key"},"description":"Stable selection identifier from an odds snapshot line, used for history and line movement."},{"name":"market_group_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Group Id"},"description":"Optional market grouping filter for history queries."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys. Requested keys this API key cannot access, or that are not bookmakers, are reported in the `X-Excluded-Bookmakers` header."},{"name":"price_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(odds|odds_no_vig|fair_odds)$","default":"odds_no_vig","title":"Price Type"},"description":"History price type to return, for example odds."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsHistoryStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"event_id":"3704597661","selection_key":"moneyline:home","resume":"1760000000000-0","points":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}},"X-Excluded-Bookmakers":{"description":"Present when the `bookmakers` filter named bookmakers this response cannot contain: comma-separated `key:reason` pairs, where reason is `not_entitled` (not included in this API key's plan or bookmaker grant) or `unknown_bookmaker` (not a key from `/bookmakers`).","schema":{"type":"string","example":"williamhill:not_entitled,bet356:unknown_bookmaker"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for line movement on one selection. This is useful for charts that should update while an event market is moving.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/odds/history/ws":{"get":{"operationId":"websocket_events_event_id_odds_history_ws","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"selection_key","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Selection Key"},"description":"Stable selection identifier from an odds snapshot line, used for history and line movement."},{"name":"market_group_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Group Id"},"description":"Optional market grouping filter for history queries."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker allow-list","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys."},{"name":"price_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(odds|odds_no_vig|fair_odds)$","default":"odds_no_vig","title":"Price Type"},"description":"History price type to return, for example odds."},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsHistoryStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","selection_key":"moneyline:home","resume":"1760000000000-0","points":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/OddsHistoryStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","selection_key":"moneyline:home","resume":"1760000000000-0","points":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/events/{event_id}/odds/history/stream","tags":["Sports odds"],"summary":"Event odds history: Stream (WebSocket)","description":"WebSocket feed for line movement on one selection. Messages mirror the history SSE stream payloads.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/exchange/orderbook/snapshot":{"get":{"tags":["Sports exchange"],"summary":"Event exchange order book: Snapshot","operationId":"exchange_orderbook_snapshot_events__event_id__exchange_orderbook_snapshot_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"exchanges","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated exchange filter: betdaq, betfair, smarkets, matchbook.","title":"Exchanges"},"description":"Comma-separated exchange allow-list. Supported values are `betdaq`, `betfair`, `smarkets`, and `matchbook`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list.","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"selection_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated selection_key allow-list.","title":"Selection Keys"},"description":"Comma-separated stable selection identifiers from an exchange order book or odds snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Price levels per back/lay side. Exchanges currently supply at most 3 levels per side; larger values return the levels available.","default":3,"title":"Depth"},"description":"Number of exchange price levels per back/lay side. Exchanges currently supply at most 3 levels per side, so values above 3 return the levels available. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"refresh","in":"query","required":false,"schema":{"type":"boolean","description":"Request bounded, demand-driven Betfair collection before returning.","default":false,"title":"Refresh"},"description":"Request bounded, demand-driven Betfair collection before returning."},{"name":"refresh_timeout_seconds","in":"query","required":false,"schema":{"type":"number","maximum":10.0,"minimum":0.5,"default":5.0,"title":"Refresh Timeout Seconds"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeOrderBookSnapshotResponse"},"examples":{"default":{"summary":"Event exchange order book: Snapshot","value":{"event_id":"3704597661","as_of_ts_ms":1760000000000,"ttl_seconds":30,"items":[{"id":"betfair::1.23456789::moneyline","event_id":"3704597661","exchange":"betfair","exchange_market_id":"1.23456789","market_key":"moneyline","market_name":"Match Odds","bet_type":"moneyline","period":"full time","home_team":"Home","away_team":"Away","status":"open","in_play":false,"total_matched":24567.12,"total_available":204.8,"total_available_source":"displayed_ladders","currency":"AUD","observed_at":"2026-08-22T08:00:00Z","selections":[{"selection_key":"moneyline:home","exchange_selection_id":"12345","selection_name":"Home","last_traded_price":2.08,"traded_volume_by_price":[{"price":2.08,"size":300.0}],"available_to_back":[{"price":2.08,"size":120.5}],"available_to_lay":[{"price":2.1,"size":84.3}],"best_back_price":2.08,"best_back_size":120.5,"best_lay_price":2.1,"best_lay_size":84.3}]}],"next_cursor":null,"resume":"1760000000000-0"}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns sports betting exchange order books for one event. Supported exchanges are betdaq, betfair, smarkets, and matchbook. Each selection includes back and lay price levels with available size, plus top-of-book summary fields such as best_back_price and best_lay_price. Market identity, team identity, source and observation timestamps, currency, total matched, total available, traded volume, and traded volume by price are retained when supplied by the exchange source. Smarkets volume is reported in GBP and includes its native double_stake_volume when available. Use `depth` to limit executable ladder levels and cache only briefly because exchange liquidity can move quickly.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/exchange/orderbook/stream":{"get":{"tags":["Sports exchange"],"summary":"Event exchange order book: Stream (SSE)","operationId":"exchange_orderbook_stream_events__event_id__exchange_orderbook_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"exchanges","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated exchange filter.","title":"Exchanges"},"description":"Comma-separated exchange allow-list. Supported values are `betdaq`, `betfair`, `smarkets`, and `matchbook`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list.","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"selection_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated selection_key allow-list.","title":"Selection Keys"},"description":"Comma-separated stable selection identifiers from an exchange order book or odds snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Price levels per back/lay side. Exchanges currently supply at most 3 levels per side; larger values return the levels available.","default":3,"title":"Depth"},"description":"Number of exchange price levels per back/lay side. Exchanges currently supply at most 3 levels per side, so values above 3 return the levels available. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/ExchangeOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for sports exchange order book changes on one event. Subscribe after reading the snapshot and pass the snapshot `resume` value as `since` to receive catch-up changes when available. Handle `delta`, `heartbeat`, and `resync`; reload the snapshot after `resync`.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/exchange/orderbook/ws":{"get":{"operationId":"websocket_events_event_id_exchange_orderbook_ws","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"exchanges","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated exchange filter.","title":"Exchanges"},"description":"Comma-separated exchange allow-list. Supported values are `betdaq`, `betfair`, `smarkets`, and `matchbook`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated market_key allow-list.","title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"selection_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated selection_key allow-list.","title":"Selection Keys"},"description":"Comma-separated stable selection identifiers from an exchange order book or odds snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Price levels per back/lay side. Exchanges currently supply at most 3 levels per side; larger values return the levels available.","default":3,"title":"Depth"},"description":"Number of exchange price levels per back/lay side. Exchanges currently supply at most 3 levels per side, so values above 3 return the levels available. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/ExchangeOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/ExchangeOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/events/{event_id}/exchange/orderbook/stream","tags":["Sports exchange"],"summary":"Event exchange order book: Stream (WebSocket)","description":"WebSocket feed for sports exchange order book changes on one event. Messages mirror the exchange order book SSE stream payloads.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/exchange/markets":{"get":{"tags":["Sports exchange"],"summary":"In-play exchange: Discover markets","description":"Lists available Betfair markets across sports, including soccer and cricket. Supply a WagerWise event ID or id_type=betfair with a native Betfair event ID. Filter using market_types; MATCH_ODDS is sorted first. Use the returned opaque market_id values with the multiplexed WebSocket; do not send Betfair market names or IDs.","operationId":"exchange_markets_events__event_id__exchange_markets_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"exchange","in":"query","required":false,"schema":{"type":"string","pattern":"^betfair$","default":"betfair","title":"Exchange"}},{"name":"id_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(wagerwise|betfair)$","description":"Namespace of event_id; Betfair IDs are numeric event IDs, not market IDs.","default":"wagerwise","title":"Id Type"},"description":"Namespace of event_id; Betfair IDs are numeric event IDs, not market IDs."},{"name":"market_types","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"description":"Optional comma-separated Betfair market types, e.g. MATCH_ODDS,OVER_UNDER_25.","title":"Market Types"},"description":"Optional comma-separated Betfair market types, e.g. MATCH_ODDS,OVER_UNDER_25."},{"name":"refresh","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Refresh"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMarketsResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/exchange/betfair/events":{"get":{"tags":["Sports exchange"],"summary":"In-play exchange: List in-play Betfair events","description":"Lists every event Betfair reports in play, including native-only events outside the WagerWise schedule. Each item has an opaque match_odds_market_id you can subscribe to on the multiplexed WebSocket without a discovery call; use markets_url for other markets. Filter with sport and scheduled. Refreshed about every 30 seconds; source_age_seconds and stale report freshness.","operationId":"betfair_in_play_events_exchange_betfair_events_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"in_play","in":"query","required":false,"schema":{"type":"boolean","description":"Only true is supported: events Betfair reports in play now.","default":true,"title":"In Play"},"description":"Only true is supported: events Betfair reports in play now."},{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Sport"},"description":"Sport filter. Use `/sports` to discover supported values."},{"name":"scheduled","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"true: only events in the WagerWise schedule; false: only native-only Betfair events.","title":"Scheduled"},"description":"true: only events in the WagerWise schedule; false: only native-only Betfair events."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BetfairInPlayEventsResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/exchange/betfair/events/{betfair_event_id}/markets":{"get":{"tags":["Sports exchange"],"summary":"In-play exchange: Discover by Betfair event ID","description":"Public Odds API operation. Authenticate with `X-API-Key`. Check timestamps before displaying prices and handle empty, stale, or suspended markets.","operationId":"betfair_event_markets_exchange_betfair_events__betfair_event_id__markets_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"betfair_event_id","in":"path","required":true,"schema":{"type":"string","title":"Betfair Event Id"}},{"name":"market_types","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Market Types"}},{"name":"refresh","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Refresh"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMarketsResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/exchange/orderbooks/ws":{"get":{"operationId":"websocket_exchange_orderbooks_ws","parameters":[],"responses":{"101":{"description":"WebSocket connection established. Send subscribe/unsubscribe JSON commands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InPlayExchangeWebSocketMessage"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-subscription-command":{"op":"subscribe","market_ids":["bfm_..."],"depth":3},"tags":["Sports exchange"],"summary":"In-play exchange: Multiplexed WebSocket","description":"One support-approved WebSocket can subscribe and unsubscribe dynamically from up to five opaque market IDs. Send {op: subscribe, market_ids: [...], depth: 3}; the server acknowledges immediately. If WagerWise holds a last-known book it is sent at once as an image with origin=cache: it can be of any age, so check freshness and source_ts. The live stream's book follows, usually within a few seconds, as an image with origin=live (cold market) or as a delta. source_ts is Betfair's publish time of the last change, observed_at is WagerWise's ingest time, and source_delayed reports Betfair delayed (180 s+ conflation) or latent data, not age. Heartbeats every 5 s carry a sync map per subscribed market: in_sync=true means the live Betfair stream confirmed within the last 15 s that the delivered book has no newer change, so an unchanged price is current. Every order book includes in_play, synced_at and in_sync. The handshake uses one API credit; connection time and logical bytes use the plan's stream quotas.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/exchange/tennis/scores/ws":{"get":{"operationId":"websocket_exchange_tennis_scores","x-websocket":true,"x-subscription-command":{"op":"subscribe","event_ids":["betfair:123"]},"responses":{"101":{"description":"WebSocket established; subscribe to discovered tennis event IDs.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/TennisScoreMessage"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["subscribed","unsubscribed","heartbeat","pong","error","warming_timeout","score_unavailable","stale","upstream_unavailable"]},"event_id":{"type":"string"},"event_ids":{"type":"array","items":{"type":"string"}},"active_event_ids":{"type":"array","items":{"type":"string"}},"warming":{"type":"array","items":{"type":"string"}},"code":{"type":"string"},"retryable":{"type":"boolean"},"ts":{"type":"integer"}}}]}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Tennis scores entitlement required.","headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"tags":["Sports exchange"],"summary":"Live tennis scores: Multiplexed WebSocket","description":"Requires X-API-Key with tennis_scores_enabled=true. Discover tennis event IDs first using exchange market discovery. Send subscribe/unsubscribe commands with event_ids (maximum 10), or ping. Opening alone starts no collection. The first score is an image; delta contains a complete replacement score. Five-second heartbeats indicate socket liveness only. Scores are ephemeral: no history or replay. received_at is our receipt time; source_timestamp is null. Scores and prices are independent observations and may be delayed or inaccurate. Nullable fields are not inferred. Handle unknown_event_ids, event_limit_exceeded, warming_timeout, score_unavailable, stale and upstream_unavailable. Quota exhaustion closes with 4429; authentication and availability use the standard stream close codes. Reconnect and subscribe again after disconnect; sequence numbers are scoped to the active router process.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/prediction-markets/orderbook/snapshot":{"get":{"tags":["Prediction markets"],"summary":"Prediction-market order book: Snapshot","operationId":"prediction_orderbook_snapshot_events__event_id__prediction_markets_orderbook_snapshot_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"providers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated provider filter: kalshi, polymarket.","title":"Providers"},"description":"Comma-separated prediction-market provider allow-list: `polymarket`, `kalshi`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"contract_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contract Ids"},"description":"Comma-separated contract ID allow-list from a prediction-market snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":3,"title":"Depth"},"description":"Number of probability price levels per bid/ask side. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictionOrderBookSnapshotResponse"},"examples":{"default":{"summary":"Prediction-market order book: Snapshot","value":{"event_id":"3704597661","as_of_ts_ms":1760000000000,"ttl_seconds":30,"items":[{"id":"polymarket::nba-example::moneyline","event_id":"3704597661","provider":"polymarket","provider_market_id":"nba-example","market_key":"moneyline","market_name":"Home vs Away","bet_type":"moneyline","period":"full time","home_team":"Home","away_team":"Away","status":"open","currency":"USD","size_unit":"contracts","total_liquidity":4200.0,"fee_model":"polymarket_sports_taker","fee_estimated":true,"observed_at":"2026-08-26T08:00:00Z","contracts":[{"contract_id":"home-contract","contract_name":"Home","outcome":"yes","side":"home","status":"open","probability_bids":[{"price":0.51,"size":120.0}],"probability_asks":[{"price":0.52,"size":95.0}],"best_bid_probability":0.51,"best_bid_size":120.0,"best_ask_probability":0.52,"best_ask_size":95.0,"gross_decimal_odds":1.92307692,"fee_adjusted_decimal_odds":1.88,"projection_eligible":true}]}],"next_cursor":null,"resume":"1760000000000-0"}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns Polymarket and Kalshi order books linked to one canonical WagerWise sports event. Each contract contains executable probability bid and ask ladders, top-of-book probability and size, the most recent trade probability when available, gross and estimated fee-adjusted decimal odds, liquidity metadata, and source freshness. Use `providers`, `market_keys`, and `contract_ids` to narrow the response and `depth` to bound each ladder. Market availability is curated to WagerWise's supported sports offering.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/events/{event_id}/prediction-markets/orderbook/stream":{"get":{"tags":["Prediction markets"],"summary":"Prediction-market order book: Stream (SSE)","operationId":"prediction_orderbook_stream_events__event_id__prediction_markets_orderbook_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"providers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Providers"},"description":"Comma-separated prediction-market provider allow-list: `polymarket`, `kalshi`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"contract_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contract Ids"},"description":"Comma-separated contract ID allow-list from a prediction-market snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":3,"title":"Depth"},"description":"Number of probability price levels per bid/ask side. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/PredictionOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for prediction-market order-book changes on one event. Read the snapshot first, then reconnect with its `resume` token as `since`. Handle `delta`, `heartbeat`, and `resync`; reload the snapshot after `resync`.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/prediction-markets/orderbook/ws":{"get":{"operationId":"websocket_events_event_id_prediction_markets_orderbook_ws","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"providers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Providers"},"description":"Comma-separated prediction-market provider allow-list: `polymarket`, `kalshi`."},{"name":"market_keys","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Keys"},"description":"Comma-separated market key allow-list for odds filters."},{"name":"contract_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contract Ids"},"description":"Comma-separated contract ID allow-list from a prediction-market snapshot."},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":3,"title":"Depth"},"description":"Number of probability price levels per bid/ask side. Use smaller values for lower latency and payload size."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"When true, include unavailable or suspended rows where the endpoint supports them."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/PredictionOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/PredictionOrderBookStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"3704597661","resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/events/{event_id}/prediction-markets/orderbook/stream","tags":["Prediction markets"],"summary":"Prediction-market order book: Stream (WebSocket)","description":"WebSocket feed for prediction-market order-book changes on one event. Messages mirror the prediction-market SSE stream payloads and use the same filters and resume semantics.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/racing/events":{"get":{"tags":["Racing events"],"summary":"Racing events: Search","operationId":"list_racing_events_racing_events_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"race_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated canonical racing types: `horse-racing`, `greyhound-racing`, or `harness-racing`. Legacy shorthand is normalized for backward compatibility.","title":"Race Type"},"description":"Comma-separated canonical racing type filters: `horse-racing`, `greyhound-racing`, or `harness-racing`. Legacy aliases such as `horse`, `thoroughbred`, `greyhound`, `dog`, `dogs`, and `harness` are normalized for backward compatibility."},{"name":"race_state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated race states.","title":"Race State"},"description":"Comma-separated racing state filters."},{"name":"race_country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated racing country codes: `AU`, `NZ`, `GB`, or `IE`. Returned combinations depend on the live racing schedule.","title":"Race Country"},"description":"Comma-separated racing country filters: `AU`, `NZ`, `GB`, or `IE`. Returned combinations depend on the live racing schedule."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated statuses.","title":"Status"},"description":"Comma-separated event lifecycle statuses. Omit for early discovery: fetching alone excludes open races that may already have prices. This is not the bookmaker odds snapshot status."},{"name":"start_from","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Unix seconds; default now-900.","title":"Start From"},"description":"Unix seconds lower bound for event start time. Use bounded windows in production polling."},{"name":"start_to","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Unix seconds; optional.","title":"Start To"},"description":"Unix seconds upper bound for event start time. Keep windows narrow for hot sync jobs."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pagination cursor: 'race_start_time:event_id'.","title":"Cursor"},"description":"Pagination cursor from the previous `next_cursor`. Keep filters identical between pages."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingEventListResponse"},"examples":{"default":{"summary":"Racing events: Search","value":{"items":[{"event_id":"race-1001","race_type":"horse-racing","race_country":"AU","race_state":"QLD","status":"open","race_start_time":1760000000,"race_venue":"Doomben","active_runners":7,"total_runners":8,"scratched_runners":1,"runner_count_source":"betfair","runner_count_updated_at_ts":1759999700,"runner_count_complete":true}],"next_cursor":null,"count":1}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Searches upcoming and live horse, greyhound, and harness racing events across Australia (`AU`), New Zealand (`NZ`), Great Britain (`GB`), and Ireland (`IE`). Use canonical race types `horse-racing`, `greyhound-racing`, and `harness-racing`; legacy shorthand is normalized for backward compatibility. Returned combinations depend on the live schedule. Racing polling should use narrow time windows, stable cursors, and shorter intervals near jump. Omit status to discover early races: status=fetching excludes events still marked open, even when early odds exist. Event lifecycle status is distinct from each bookmaker odds snapshot status. Runner counts prefer Betfair's complete scratch-aware field, fall back to another bookmaker or the schedule, and expose source, timestamp, and completeness metadata. Racing includes every available bookmaker on every plan: the API key's odds and betting-opportunity bookmaker selections do not filter racing events, odds, streams, or links.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/racing/events/stream":{"get":{"tags":["Racing events"],"summary":"Racing events: Stream (SSE)","operationId":"stream_racing_events_racing_events_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingEventsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for racing event inserts, updates, and removals. Store resume tokens and reload the event list if a stream asks the client to resync.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":2,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/racing/events/ws":{"get":{"operationId":"websocket_racing_events_ws","parameters":[{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingEventsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingEventsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","changes":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/racing/events/stream","tags":["Racing events"],"summary":"Racing events: Stream (WebSocket)","description":"WebSocket feed for racing event inserts, updates, and removals. Messages mirror the racing events SSE feed.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":2,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/racing/events/{event_id}":{"get":{"tags":["Racing events"],"summary":"Racing events: Event details","operationId":"get_racing_event_racing_events__event_id__get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingEventDetail"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the current racing event record for a canonical race ID.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/racing/events/{event_id}/odds":{"get":{"tags":["Racing odds"],"summary":"Racing odds: Snapshot","operationId":"get_racing_odds_snapshot_racing_events__event_id__odds_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"bookmakers","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated bookmaker filter.","title":"Bookmakers"},"description":"Comma-separated bookmaker allow-list. Use `/bookmakers` to discover supported keys."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"Include bookmaker_link when available, independently of raw payload. Compact clients omit links by default. false removes links including nested raw links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"Include bookmaker-specific payload. Compact clients default to false and receive runners[].win_odds; Sportsbet raw WIN prices are payload.horse_data[].odds."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"Include source metadata such as updated_at_ts (Unix seconds). Compact clients omit it by default."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"Include bookmaker snapshots without compact WIN or PLACE runner prices. This does not restrict odds to status fetching; early status ok may contain valid prices."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingOddsSnapshotResponse"},"examples":{"default":{"summary":"Racing odds: Snapshot","value":{"event_id":"race-1001","as_of_ts_ms":1760000000000,"active_runners":7,"total_runners":8,"scratched_runners":1,"runner_count_source":"betfair","runner_count_updated_at_ts":1759999700,"runner_count_complete":true,"items":[{"bookmaker_name":"betfair","race_id":"race-1001","status":"ok","total_matched":24567.12,"runners":[{"runner_number":"1","runner_name":"Example Runner","win_odds":3.4,"place_odds":1.65,"traded_volume":4100.0}]}],"resume":"1760000000000-0"}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns bookmaker odds snapshots for one racing event. Cache the last good snapshot with its timestamp and prefer streams for near-jump realtime displays. Compact WIN prices are at items[].runners[].win_odds. Exchange WIN-market volume is at items[].total_matched and matched runner volume, when supplied, is at items[].runners[].traded_volume. These are cumulative traded amounts, not current executable depth. Sportsbet raw prices, when requested, are at items[].payload.horse_data[].odds. Early odds status ok and near-jump status fetching can both contain valid prices. Top-level active_runners, total_runners, scratched_runners, runner_count_source, runner_count_updated_at_ts, and runner_count_complete describe the best available field state. Every available racing bookmaker is returned on every plan; the API key's odds and betting-opportunity bookmaker selections do not filter racing odds. Use the bookmakers parameter to narrow the response. Request include_source=true for snapshot timestamps and include_links=true for bookmaker_link, independently of include_raw_payload.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/racing/events/{event_id}/odds/stream":{"get":{"tags":["Racing odds"],"summary":"Racing odds: Stream (SSE)","operationId":"stream_racing_odds_racing_events__event_id__odds_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"Include bookmaker_link when available, independently of raw payload. Compact clients omit links by default. false removes links including nested raw links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"Include bookmaker-specific payload. Compact clients default to false and receive runners[].win_odds; Sportsbet raw WIN prices are payload.horse_data[].odds."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"Include source metadata such as updated_at_ts (Unix seconds). Compact clients omit it by default."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"Include bookmaker snapshots without compact WIN or PLACE runner prices. This does not restrict odds to status fetching; early status ok may contain valid prices."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID.","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingOddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"event_id":"race-1001","resume":"1760000000000-0","changes":[{"op":"upsert","bookmaker_name":"sportsbet","snapshot":{"bookmaker_name":"betfair","race_id":"race-1001","status":"ok","total_matched":24567.12,"runners":[{"runner_number":"1","runner_name":"Example Runner","win_odds":3.4,"place_odds":1.65,"traded_volume":4100.0}]}}]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for racing odds changes on one event. Reconnect with `since=<last_resume>` and reload the snapshot after `resync`. Each changes[].snapshot uses the same compact runner fields, link flags and odds status meanings as the racing odds snapshot endpoint for compact clients. Non-compact clients with include_raw_payload=true receive raw bookmaker data directly in snapshot (Sportsbet: snapshot.horse_data[].odds), without a payload wrapper.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/racing/events/{event_id}/odds/ws":{"get":{"operationId":"websocket_racing_events_event_id_odds_ws","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"Include bookmaker_link when available, independently of raw payload. Compact clients omit links by default. false removes links including nested raw links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"Include bookmaker-specific payload. Compact clients default to false and receive runners[].win_odds; Sportsbet raw WIN prices are payload.horse_data[].odds."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"Include source metadata such as updated_at_ts (Unix seconds). Compact clients omit it by default."},{"name":"include_unavailable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Unavailable"},"description":"Include bookmaker snapshots without compact WIN or PLACE runner prices. This does not restrict odds to status fetching; early status ok may contain valid prices."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Redis stream ID.","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."},{"name":"max_batch","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Max Batch"},"description":"Maximum stream messages to read per batch. Default is 500; use smaller batches for low-latency clients."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingOddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"race-1001","resume":"1760000000000-0","changes":[{"op":"upsert","bookmaker_name":"sportsbet","snapshot":{"bookmaker_name":"betfair","race_id":"race-1001","status":"ok","total_matched":24567.12,"runners":[{"runner_number":"1","runner_name":"Example Runner","win_odds":3.4,"place_odds":1.65,"traded_volume":4100.0}]}}]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/RacingOddsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"event_id":"race-1001","resume":"1760000000000-0","changes":[{"op":"upsert","bookmaker_name":"sportsbet","snapshot":{"bookmaker_name":"betfair","race_id":"race-1001","status":"ok","total_matched":24567.12,"runners":[{"runner_number":"1","runner_name":"Example Runner","win_odds":3.4,"place_odds":1.65,"traded_volume":4100.0}]}}]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/racing/events/{event_id}/odds/stream","tags":["Racing odds"],"summary":"Racing odds: Stream (WebSocket)","description":"WebSocket feed for racing odds changes on one event. Messages mirror the racing odds SSE feed.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/bets/snapshot":{"get":{"tags":["Betting opportunities"],"summary":"Betting opportunities: Snapshot","operationId":"snapshot_bets_snapshot_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"strategies","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated strategies or 'all'","default":"all","title":"Strategies"},"description":"Comma-separated betting strategies or `all`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20000,"minimum":1,"default":2000,"title":"Limit"},"description":"Maximum items to return. Respect the caps returned by `/limits`."},{"name":"event_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Live bet source: active, legacy, or admin-only hybrid","title":"Source"},"description":"Live bet source: active, legacy, or admin-only hybrid"},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BetsSnapshotResponse"},"examples":{"default":{"summary":"Betting opportunities: Snapshot","value":{"items":[{"id":"example-positive-ev","strategy":"pos_ev","event_id":"3704597661","bookmaker_name":"Bet365","selection_key":"moneyline:home","odds":2.1,"ev":7.7}],"resume":"{\"pos_ev\":\"1760000000000-0\"}"}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns current betting opportunities by strategy. Use `strategies`, `limit`, and `event_id` to keep the payload scoped to what your product needs. Poll at a bounded interval, cache the last good response, and show execution-risk language before any user-facing bet action.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/bets/stream":{"get":{"tags":["Betting opportunities"],"summary":"Betting opportunities: Stream (SSE)","operationId":"stream_bets_stream_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"strategies","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"all","title":"Strategies"},"description":"Comma-separated betting strategies or `all`."},{"name":"event_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Live bet source: active, legacy, or admin-only hybrid","title":"Source"},"description":"Live bet source: active, legacy, or admin-only hybrid"},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Resume token from /snapshot (JSON mapping strategy->id)","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."}],"responses":{"200":{"description":"Server-Sent Events stream. Each message has an event name and JSON data payload.","content":{"text/event-stream":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/BetsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Decoded delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","events":[]}}},"heartbeat":{"summary":"Decoded heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Decoded resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Server-Sent Events feed for betting opportunity inserts, updates, and removals. Use this for alerting instead of high-frequency snapshot polling. Source-binding response headers identify the requested logical live-bet source and per-strategy effective sources.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/bets/ws":{"get":{"operationId":"websocket_bets_ws","parameters":[{"name":"strategies","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"all","title":"Strategies"},"description":"Comma-separated betting strategies or `all`."},{"name":"event_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"description":"Canonical event or race identifier from an event list response."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Live bet source: active, legacy, or admin-only hybrid","title":"Source"},"description":"Live bet source: active, legacy, or admin-only hybrid"},{"name":"price_fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Fields"},"description":"`odds`, `odds,novig`, `odds,fair`, or `all`. Compact clients default to `odds`; existing clients default to current full pricing fields."},{"name":"include_links","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Links"},"description":"When true, include bookmaker/deep-link fields such as match links and racing links."},{"name":"include_raw_payload","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Raw Payload"},"description":"When true, include raw stored payload/data objects where the endpoint exposes them."},{"name":"include_source","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Source"},"description":"When true, include per-line/per-bookmaker provenance and capture metadata. Top-level freshness fields are always kept."},{"name":"include_debug_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Debug Ids"},"description":"When true, include internal/subgroup/opposing IDs useful for reconciliation."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Resume token from /snapshot (JSON mapping strategy->id)","title":"Since"},"description":"Resume token from a previous snapshot or stream message. Pass it after reconnecting."},{"name":"catchup","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Catchup"},"description":"When true, return available missed stream events after `since` before waiting for new events."},{"name":"heartbeat_sec","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":5,"default":15,"title":"Heartbeat Sec"},"description":"Maximum seconds between messages: a `heartbeat` is sent whenever this long passes without another message. Valid range is 5-120."}],"responses":{"101":{"description":"WebSocket connection established. Messages are JSON objects.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/BetsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","events":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"200":{"description":"OpenAPI tooling compatibility response schema. Runtime WebSocket connections upgrade with 101.","content":{"application/json":{"schema":{"type":"object","description":"Decoded stream message. SSE transports this as an event line plus JSON data; WebSockets send it as JSON.","required":["event","data"],"properties":{"event":{"type":"string","enum":["delta","heartbeat","resync"]},"data":{"oneOf":[{"$ref":"#/components/schemas/BetsStreamEvent"},{"$ref":"#/components/schemas/StreamHeartbeat"},{"$ref":"#/components/schemas/StreamResyncEvent"}]}}},"examples":{"delta":{"summary":"Delta message","value":{"event":"delta","data":{"resume":"1760000000000-0","events":[]}}},"heartbeat":{"summary":"Heartbeat message","value":{"event":"heartbeat","data":{}}},"resync":{"summary":"Resync message","value":{"event":"resync","data":{"event_id":"3704597661","resume":null,"reason":"trimmed"}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-websocket":true,"x-stream-equivalent":"/bets/stream","tags":["Betting opportunities"],"summary":"Betting opportunities: Stream (WebSocket)","description":"WebSocket feed for betting opportunity inserts, updates, and removals. The accept handshake includes source-binding headers matching the SSE stream.","security":[{"ApiKeyAuth":[]}],"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops.","x-stream-metering":{"stream_units":1,"stream_hours_formula":"stream_units * open_seconds / 3600","logical_bytes_metered":true,"quota_policy":"hard_cap","applies_to":"authenticated API-key connections"}}},"/events/{event_id}/results":{"get":{"tags":["Results"],"summary":"Results: Event result","operationId":"get_event_results_events__event_id__results_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultItem"},"examples":{"default":{"summary":"Results: Event result","value":{"event_id":"3704597661","status":"final","result":{"home_score":24,"away_score":18}}}}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"description":"Returns the latest known result for a sports event, or `pending` until settled. Poll every 1-5 minutes after start, then back off once the event is final.","x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/racing/events/{event_id}/results":{"get":{"tags":["Results"],"summary":"GET racing events event_id results","description":"Public Odds API operation. Authenticate with `X-API-Key`. Check timestamps before displaying prices and handle empty, stale, or suspended markets.","operationId":"get_racing_event_results_racing_events__event_id__results_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"},"description":"Canonical event or race identifier from an event list response."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingResultItem"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}},"/racing/results":{"post":{"tags":["Results"],"summary":"POST racing results","description":"Public Odds API operation. Authenticate with `X-API-Key`. Check timestamps before displaying prices and handle empty, stale, or suspended markets.","operationId":"get_racing_results_bulk_racing_results_post","security":[{"ApiKeyAuth":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingResultsListRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RacingResultsListResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"400":{"description":"Invalid request parameters or body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"403":{"description":"Credentials are valid but do not allow this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"404":{"description":"Resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded.","headers":{"Retry-After":{"description":"Seconds to wait before retrying when supplied by the limiter.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Request bucket capacity for the active limiter bucket when supplied.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Approximate remaining requests in the active limiter bucket when supplied.","schema":{"type":"integer","minimum":0}},"X-RateLimit-Bucket":{"description":"Limiter bucket name that produced the response when supplied.","schema":{"type":"string"}},"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"headers":{"X-Request-ID":{"description":"Request identifier: the client's `X-Request-ID` when it is 1-128 characters of letters, digits, `.`, `_`, `:` or `-`, otherwise a generated UUID. Quote it when contacting support.","schema":{"type":"string"}}}}},"x-rate-limit-note":"Handle HTTP 429 with backoff and avoid tight polling loops."}}},"components":{"schemas":{"BetfairInPlayEvent":{"properties":{"betfair_event_id":{"type":"string","title":"Betfair Event Id","description":"Native numeric Betfair event ID."},"event_id":{"type":"string","title":"Event Id","description":"Stream binding: the WagerWise event ID, or betfair:<id> for native-only events."},"wagerwise_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wagerwise Event Id","description":"Set when the event is in the WagerWise schedule."},"sport":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"event_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Name"},"competition_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Competition Name"},"start_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time"},"in_play":{"type":"boolean","title":"In Play","default":true},"match_odds_market_id":{"type":"string","title":"Match Odds Market Id","description":"Opaque MATCH_ODDS market_id to subscribe with directly."},"runners":{"items":{"type":"string"},"type":"array","title":"Runners"},"markets_url":{"type":"string","title":"Markets Url","description":"Discovery URL for every Betfair market on this event."}},"type":"object","required":["betfair_event_id","event_id","match_odds_market_id","markets_url"],"title":"BetfairInPlayEvent"},"BetfairInPlayEventsResponse":{"properties":{"exchange":{"type":"string","title":"Exchange","default":"betfair"},"items":{"items":{"$ref":"#/components/schemas/BetfairInPlayEvent"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total","description":"In-play events matching the filters before offset/limit."},"observed_at":{"type":"integer","title":"Observed At","description":"Unix seconds when Betfair was read."},"source_age_seconds":{"type":"integer","title":"Source Age Seconds"},"stale":{"type":"boolean","title":"Stale","description":"True when the list is older than three observer cycles."},"subscription":{"$ref":"#/components/schemas/ExchangeMarketSubscription"}},"type":"object","required":["items","count","total","observed_at","source_age_seconds","stale","subscription"],"title":"BetfairInPlayEventsResponse"},"BookmakersResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"items":{"items":{"type":"string"},"type":"array","title":"Items"}},"type":"object","required":["event_id","items"],"title":"BookmakersResponse"},"CoverageBookmaker":{"properties":{"bookmaker":{"type":"string","title":"Bookmaker"},"country_codes":{"items":{"type":"string"},"type":"array","title":"Country Codes"}},"type":"object","required":["bookmaker"],"title":"CoverageBookmaker"},"CoverageLeague":{"properties":{"sport":{"type":"string","title":"Sport"},"league":{"type":"string","title":"League"}},"type":"object","required":["sport","league"],"title":"CoverageLeague"},"CoverageMarket":{"properties":{"bookmaker":{"type":"string","title":"Bookmaker"},"sport":{"type":"string","title":"Sport"},"league":{"type":"string","title":"League"},"bet_type":{"type":"string","title":"Bet Type"},"metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metric"},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period"},"last_seen_at":{"type":"string","title":"Last Seen At"},"sample_event_id":{"type":"string","title":"Sample Event Id"}},"type":"object","required":["bookmaker","sport","league","bet_type","last_seen_at","sample_event_id"],"title":"CoverageMarket"},"CoverageResponse":{"properties":{"as_of":{"type":"string","title":"As Of"},"bookmakers":{"items":{"$ref":"#/components/schemas/CoverageBookmaker"},"type":"array","title":"Bookmakers"},"sports":{"items":{"type":"string"},"type":"array","title":"Sports"},"leagues":{"items":{"$ref":"#/components/schemas/CoverageLeague"},"type":"array","title":"Leagues"},"markets":{"items":{"$ref":"#/components/schemas/CoverageMarket"},"type":"array","title":"Markets"},"source":{"$ref":"#/components/schemas/CoverageSource"}},"type":"object","required":["as_of","source"],"title":"CoverageResponse"},"CoverageSource":{"properties":{"markets_are_approximate":{"type":"boolean","title":"Markets Are Approximate","default":true},"lookback_days":{"type":"integer","title":"Lookback Days"}},"type":"object","required":["lookback_days"],"title":"CoverageSource"},"EventDetail":{"properties":{"event_id":{"type":"string","title":"Event Id"},"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["event_id","data"],"title":"EventDetail"},"EventExchangeLive":{"properties":{"exchange":{"type":"string","title":"Exchange","default":"betfair"},"betfair_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Betfair Event Id","description":"Native numeric Betfair event ID."},"in_play":{"type":"boolean","title":"In Play","description":"Betfair currently reports this event in play.","default":false},"observed_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Observed At","description":"Unix seconds of the in-play observation."},"match_odds_market_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Odds Market Id","description":"Opaque MATCH_ODDS market_id; subscribe with it directly on /v1/exchange/orderbooks/ws."},"stream_ready":{"type":"boolean","title":"Stream Ready","description":"match_odds_market_id can be subscribed now without discovery.","default":false},"markets_url":{"type":"string","title":"Markets Url","description":"Discovery URL for every Betfair market on this event."}},"type":"object","required":["markets_url"],"title":"EventExchangeLive","description":"Betfair shortcut on live-discovery results for in-play exchange clients."},"EventListHint":{"properties":{"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message"},"count":{"type":"integer","title":"Count","default":0},"see":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"See"}},"type":"object","required":["code","message"],"title":"EventListHint"},"EventListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/EventSummary"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"count":{"type":"integer","title":"Count"},"hint":{"anyOf":[{"$ref":"#/components/schemas/EventListHint"},{"type":"null"}],"description":"Guidance when a strict in_play filter excluded started but unconfirmed events."}},"type":"object","required":["items","count"],"title":"EventListResponse"},"EventSummary":{"properties":{"event_id":{"type":"string","title":"Event Id","description":"Canonical event identifier (game_masterID)."},"sport":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"league":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League","description":"League name representation."},"start_time":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Time","description":"Unix seconds."},"home_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Home Team"},"away_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Away Team"},"event_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State","description":"Effective lifecycle state, including inferred start_time_passed."},"event_state_certainty":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State Certainty"},"event_state_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State Source"},"state_observed_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"State Observed At","description":"Unix seconds."},"actual_started_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Actual Started At","description":"Unix seconds."},"last_live_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Last Live At","description":"Unix seconds."},"finished_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Finished At","description":"Unix seconds."},"live_candidate":{"type":"boolean","title":"Live Candidate","default":false},"event_state_stale":{"type":"boolean","title":"Event State Stale","default":false},"live_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Live Status","description":"Plain-language status: upcoming, started (start time passed, not confirmed live), live (fresh live observation), finished, cancelled, postponed or unknown."},"has_available_bets":{"type":"boolean","title":"Has Available Bets","description":"Whether the event currently has at least one live normalized odds line.","default":false},"last_capture":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Last Capture","description":"Unix seconds."},"bookmakers":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Bookmakers","description":"Bookmaker -> odds_data_id."},"league_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League Image Url","description":"Azure-hosted league image URL when configured for this league."},"league_image_asset_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League Image Asset Slug","description":"Storage slug for the configured Azure-hosted league image."},"league_country_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League Country Code","description":"League country: ISO 3166-1 alpha-2, GB-ENG/GB-SCT/GB-WLS for UK nations, or INT for international competitions."},"league_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League Country","description":"League country name, or the region for INT competitions (for example `Europe`)."},"home_team_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Home Team Logo Url","description":"Azure-hosted home-team logo URL when matched for this event."},"away_team_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Away Team Logo Url","description":"Azure-hosted away-team logo URL when matched for this event."},"team_logo_manifest_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Team Logo Manifest Url","description":"Azure-hosted per-league team-logo manifest URL when configured."},"opportunity_counts":{"anyOf":[{"$ref":"#/components/schemas/OpportunityCounts"},{"type":"null"}],"description":"Aggregate live opportunity counts when requested."},"exchange":{"anyOf":[{"$ref":"#/components/schemas/EventExchangeLive"},{"type":"null"}],"description":"Betfair live shortcut; lifecycle/live queries by in-play exchange clients only."}},"type":"object","required":["event_id"],"title":"EventSummary"},"ExchangeMarket":{"properties":{"market_id":{"type":"string","title":"Market Id","description":"Stable opaque ID to pass to the multiplexed orderbook WebSocket."},"event_id":{"type":"string","title":"Event Id","description":"Streaming event identity; may be betfair:<id> for events outside the schedule."},"wagerwise_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wagerwise Event Id"},"betfair_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Betfair Event Id"},"exchange":{"type":"string","title":"Exchange"},"sport":{"type":"string","title":"Sport"},"market_key":{"type":"string","title":"Market Key"},"bet_type":{"type":"string","title":"Bet Type"},"metric":{"type":"string","title":"Metric"},"period":{"type":"string","title":"Period"},"source_market_type":{"type":"string","title":"Source Market Type"},"betting_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Betting Type"},"market_name":{"type":"string","title":"Market Name"},"event_name":{"type":"string","title":"Event Name"},"competition_name":{"type":"string","title":"Competition Name"},"start_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time"},"in_play_supported":{"type":"boolean","title":"In Play Supported"},"ladder_depth_max":{"type":"integer","title":"Ladder Depth Max"},"number_of_winners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Winners"},"total_matched":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Matched"},"runners":{"items":{"$ref":"#/components/schemas/ExchangeMarketRunner"},"type":"array","title":"Runners"}},"type":"object","required":["market_id","event_id","exchange","sport","market_key","bet_type","metric","period","source_market_type","market_name","event_name","competition_name","in_play_supported","ladder_depth_max"],"title":"ExchangeMarket"},"ExchangeMarketRunner":{"properties":{"selection_id":{"type":"string","title":"Selection Id"},"name":{"type":"string","title":"Name"},"handicap":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Handicap"},"sort_priority":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sort Priority"}},"type":"object","required":["selection_id","name"],"title":"ExchangeMarketRunner"},"ExchangeMarketSubscription":{"properties":{"websocket_url":{"type":"string","title":"Websocket Url"},"command":{"additionalProperties":true,"type":"object","title":"Command"},"max_markets_per_connection":{"type":"integer","title":"Max Markets Per Connection"}},"type":"object","required":["websocket_url","command","max_markets_per_connection"],"title":"ExchangeMarketSubscription"},"ExchangeMarketsResponse":{"properties":{"score_subscription":{"anyOf":[{"$ref":"#/components/schemas/TennisScoreSubscription"},{"type":"null"}]},"event_id":{"type":"string","title":"Event Id"},"exchange":{"type":"string","title":"Exchange"},"count":{"type":"integer","title":"Count"},"available_market_types":{"items":{"type":"string"},"type":"array","title":"Available Market Types"},"markets":{"items":{"$ref":"#/components/schemas/ExchangeMarket"},"type":"array","title":"Markets"},"subscription":{"$ref":"#/components/schemas/ExchangeMarketSubscription"}},"type":"object","required":["event_id","exchange","count","available_market_types","markets","subscription"],"title":"ExchangeMarketsResponse"},"ExchangeOrderBookItem":{"properties":{"id":{"type":"string","title":"Id"},"market_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Id"},"event_id":{"type":"string","title":"Event Id"},"exchange":{"type":"string","title":"Exchange"},"exchange_market_id":{"type":"string","title":"Exchange Market Id"},"source_market_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Market Type"},"sport":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"betting_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Betting Type"},"market_key":{"type":"string","title":"Market Key"},"market_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Name"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"bet_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bet Type"},"period":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Period"},"period_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Str"},"metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metric"},"line":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line"},"home_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Home Team"},"away_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Away Team"},"home_team_names":{"items":{"type":"string"},"type":"array","title":"Home Team Names"},"away_team_names":{"items":{"type":"string"},"type":"array","title":"Away Team Names"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"in_play":{"type":"boolean","title":"In Play","default":false},"total_matched":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Matched","description":"Exchange-native matched or displayed market volume."},"total_available":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Available","description":"Native or displayed-ladder total currently available market liquidity."},"total_available_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Total Available Source","description":"Whether total_available is exchange-native or summed from displayed ladders."},"traded_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Traded Volume","description":"Exchange-native traded market volume."},"double_stake_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Double Stake Volume","description":"Twice the back stake for each execution, when supplied by Smarkets."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency for monetary volume fields, such as GBP for Smarkets."},"source_ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ts","description":"Exchange publish time of the most recent change to this book (Betfair stream `pt`). It is not the time WagerWise sent the message; see observed_at and synced_at."},"source_age_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Source Age Seconds"},"freshness":{"type":"string","title":"Freshness","description":"Price observation state: live (changed within the freshness window, or confirmed current by in_sync), warming, or stale.","default":"stale"},"actively_collected":{"type":"boolean","title":"Actively Collected","default":false},"synced_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Synced At","description":"Betfair stream clock (UTC) at the latest confirmation that this market had no newer change. Only set for books delivered by the live Betfair stream."},"sync_age_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sync Age Seconds","description":"Seconds since WagerWise received that confirmation."},"in_sync":{"type":"boolean","title":"In Sync","description":"True when the live Betfair stream confirmed this actively collected book within the last 15 seconds and Betfair did not flag its stream as latent. An unchanged price with an old source_ts is then current.","default":false},"source_delayed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Source Delayed","description":"True when Betfair delivers delayed data (conflation of 180 s or more) or flagged its stream as latent when this book was published. It does not describe the age of the book."},"source_conflate_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Conflate Ms"},"observed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observed At","description":"UTC timestamp when WagerWise observed this order book."},"selections":{"items":{"$ref":"#/components/schemas/ExchangeSelectionBook"},"type":"array","title":"Selections"}},"type":"object","required":["id","event_id","exchange","exchange_market_id","market_key","period"],"title":"ExchangeOrderBookItem"},"ExchangeOrderBookSnapshotResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"As Of Ts Ms"},"ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttl Seconds"},"items":{"items":{"$ref":"#/components/schemas/ExchangeOrderBookItem"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"resume":{"type":"string","title":"Resume","description":"Redis stream ID to resume from; pass as 'since' to /stream."},"refresh_state":{"type":"string","title":"Refresh State","default":"not_requested"},"fresh_count":{"type":"integer","title":"Fresh Count","default":0},"stale_count":{"type":"integer","title":"Stale Count","default":0},"warming_count":{"type":"integer","title":"Warming Count","default":0}},"type":"object","required":["event_id","resume"],"title":"ExchangeOrderBookSnapshotResponse"},"ExchangePriceLevel":{"properties":{"price":{"type":"number","title":"Price"},"size":{"type":"number","title":"Size"}},"type":"object","required":["price","size"],"title":"ExchangePriceLevel"},"ExchangeSelectionBook":{"properties":{"selection_key":{"type":"string","title":"Selection Key"},"exchange_selection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange Selection Id"},"selection_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selection Name"},"handicap":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Handicap"},"side":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Side"},"line":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line"},"player_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Player Name"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"last_traded_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Last Traded Price"},"traded_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Traded Volume"},"traded_volume_by_price":{"items":{"$ref":"#/components/schemas/ExchangePriceLevel"},"type":"array","title":"Traded Volume By Price"},"available_to_back":{"items":{"$ref":"#/components/schemas/ExchangePriceLevel"},"type":"array","title":"Available To Back"},"available_to_lay":{"items":{"$ref":"#/components/schemas/ExchangePriceLevel"},"type":"array","title":"Available To Lay"},"best_back_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Back Price"},"best_back_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Back Size"},"best_lay_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Lay Price"},"best_lay_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Lay Size"}},"type":"object","required":["selection_key"],"title":"ExchangeSelectionBook"},"ExcludedBookmaker":{"properties":{"key":{"type":"string","title":"Key","description":"Bookmaker key, lower-cased."},"reason":{"type":"string","title":"Reason","description":"`not_entitled`, `unknown_bookmaker` or `stale`."},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"For `stale`: `age` (last accepted too long ago), `started` (only pre-match prices after kickoff) or `unknown` (prices without an acceptance time)."},"as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"As Of Ts Ms","description":"For `stale`: the bookmaker's last acceptance time."}},"type":"object","required":["key","reason"],"title":"ExcludedBookmaker"},"FairPrice":{"properties":{"available":{"type":"boolean","title":"Available"},"fair_odds":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Fair Odds"},"implied_probability":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Implied Probability","description":"Reciprocal of fair decimal odds; not unconditional win probability for push or partial-settlement markets."},"reference_count":{"type":"integer","maximum":256.0,"minimum":0.0,"title":"Reference Count"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","required":["available","reference_count"],"title":"FairPrice"},"FairPricesResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"schema_version":{"type":"string","title":"Schema Version","default":"fair-prices.v1"},"snapshot_id":{"type":"string","title":"Snapshot Id"},"input_revision":{"type":"integer","title":"Input Revision"},"reference_policy":{"type":"string","title":"Reference Policy","default":"all_eligible_reference_books"},"items":{"items":{"$ref":"#/components/schemas/FairSelection"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"complete":{"type":"boolean","title":"Complete"}},"type":"object","required":["event_id","snapshot_id","input_revision","items","complete"],"title":"FairPricesResponse"},"FairSelection":{"properties":{"selection_id":{"type":"string","maxLength":80,"pattern":"^fp1_[a-f0-9]+$","title":"Selection Id"},"bet_type":{"type":"string","maxLength":256,"title":"Bet Type"},"market_family":{"type":"string","maxLength":256,"title":"Market Family"},"period":{"type":"integer","title":"Period"},"period_str":{"type":"string","maxLength":128,"title":"Period Str"},"metric":{"type":"string","maxLength":128,"title":"Metric"},"line":{"type":"string","maxLength":512,"title":"Line"},"player_name":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Player Name"},"team_subject":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Team Subject"},"selection_keys":{"items":{"type":"string"},"type":"array","maxItems":256,"title":"Selection Keys"},"market_group_ids":{"items":{"type":"string"},"type":"array","maxItems":256,"title":"Market Group Ids"},"prices":{"additionalProperties":{"additionalProperties":{"$ref":"#/components/schemas/FairPrice"},"type":"object"},"type":"object","title":"Prices"},"computed_at_ms":{"type":"integer","exclusiveMinimum":0.0,"title":"Computed At Ms"},"expires_at_ms":{"type":"integer","exclusiveMinimum":0.0,"title":"Expires At Ms"},"oldest_observation_at_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Oldest Observation At Ms"},"newest_observation_at_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Newest Observation At Ms"}},"type":"object","required":["selection_id","bet_type","market_family","period","period_str","metric","line","prices","computed_at_ms","expires_at_ms"],"title":"FairSelection"},"OddLine":{"properties":{"id":{"type":"string","title":"Id"},"event_id":{"type":"string","title":"Event Id"},"bookmaker":{"type":"string","title":"Bookmaker"},"bookmaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bookmaker Name"},"source_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Type"},"exchange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange"},"exchange_market_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange Market Id"},"exchange_selection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange Selection Id"},"selection_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selection Key"},"market_group_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Group Id"},"market_key":{"type":"string","title":"Market Key"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"bet_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bet Type","description":"Market family, e.g. moneyline, total, spread. MMA/UFC fight markets: `method of victory` and `method of victory 7w` (line is the method: ko/tko, ko/tko/dq, submission, decision), `yes/no` (goes the distance, wins inside the distance, wins by method, wins/ends in round; see selection_parameters.predicate), `round betting` and `method and round` (selection_parameters.rounds/methods). MMA total rounds is `total` with metric `rounds`."},"period":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Period"},"period_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Str"},"metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metric","description":"What the line measures, e.g. points, goals, rounds. MMA fight markets use `standard`; over/under total rounds uses `rounds`."},"line":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line"},"side":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Side"},"player_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Player Name"},"selection_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selection Name"},"market_contract":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Market Contract","description":"Versioned settlement contract and part of market identity. Categorical contracts describe structured outcomes. The reviewed soccer team-total contract excludes own goals and is odds-only; never combine it with ordinary scoreboard totals."},"capabilities":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Capabilities","description":"Effective permissions derived from the validated quote contract. Contract-specific values override ordinary bet-family capabilities; supplied source flags cannot grant permissions."},"selection_parameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Selection Parameters","description":"Structured categorical outcome. Soccer examples: results, home_goals/away_goals, half_time/full_time, result and btts. MMA examples: predicate, methods and rounds. Outcome checkpoints do not change the enclosing period."},"number_of_outcomes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Outcomes"},"odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds"},"odds_no_vig":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig"},"odds_no_vig_multiplicative_method":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig Multiplicative Method"},"odds_no_vig_additive_method":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig Additive Method"},"odds_no_vig_power_method":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig Power Method"},"odds_no_vig_shin_method":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig Shin Method"},"fair_odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fair Odds"},"main_line_eligible":{"type":"boolean","title":"Main Line Eligible","default":true},"best_back_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Back Price"},"best_back_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Back Size"},"best_lay_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Lay Price"},"best_lay_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Lay Size"},"last_traded_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Last Traded Price"},"traded_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Traded Volume"},"total_matched":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Matched"},"liquidity_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Liquidity Source"},"liquidity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Liquidity"},"back_liquidity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Back Liquidity"},"lay_liquidity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lay Liquidity"},"is_available":{"type":"boolean","title":"Is Available","default":true}},"type":"object","required":["id","event_id","bookmaker","market_key","period"],"title":"OddLine"},"OddsHistoryMeta":{"properties":{"from_ts":{"type":"string","format":"date-time","title":"From Ts"},"to_ts":{"type":"string","format":"date-time","title":"To Ts"},"available_price_types":{"items":{"type":"string"},"type":"array","title":"Available Price Types"},"source":{"type":"string","title":"Source","default":"unknown"},"degraded":{"type":"boolean","title":"Degraded","default":false},"degraded_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degraded Reason"}},"type":"object","required":["from_ts","to_ts","available_price_types"],"title":"OddsHistoryMeta"},"OddsHistoryPoint":{"properties":{"tick_ts":{"type":"string","format":"date-time","title":"Tick Ts"},"is_available":{"type":"boolean","title":"Is Available"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds"},"odds_no_vig":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Odds No Vig"},"fair_odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fair Odds"}},"type":"object","required":["tick_ts","is_available"],"title":"OddsHistoryPoint"},"OddsHistoryResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"selection_key":{"type":"string","title":"Selection Key"},"price_type":{"type":"string","title":"Price Type"},"series":{"items":{"$ref":"#/components/schemas/OddsHistorySeries"},"type":"array","title":"Series"},"meta":{"$ref":"#/components/schemas/OddsHistoryMeta"}},"type":"object","required":["event_id","selection_key","price_type","series","meta"],"title":"OddsHistoryResponse"},"OddsHistorySeries":{"properties":{"bookmaker_name":{"type":"string","title":"Bookmaker Name"},"points":{"items":{"$ref":"#/components/schemas/OddsHistoryPoint"},"type":"array","title":"Points"}},"type":"object","required":["bookmaker_name","points"],"title":"OddsHistorySeries"},"OddsSnapshotResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"As Of Ts Ms","description":"Event-wide clock: time the API accepted the latest snapshot or authoritative subset from ANY bookmaker on this event, including bookmakers this response does not return. Do not use it to judge specific bookmakers; use bookmaker_as_of_ts_ms."},"snapshot_capture_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Snapshot Capture Ts Ms","description":"Time the snapshot producer completed the latest published event capture."},"bookmaker_as_of_ts_ms":{"additionalProperties":{"type":"integer"},"type":"object","title":"Bookmaker As Of Ts Ms","description":"Last API acceptance time for each bookmaker included in this response. This is the per-bookmaker freshness signal; one capture refreshes all of a bookmaker's markets on the event together."},"oldest_bookmaker_as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Oldest Bookmaker As Of Ts Ms","description":"Oldest acceptance time among bookmaker_as_of_ts_ms values."},"newest_bookmaker_as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Newest Bookmaker As Of Ts Ms","description":"Newest acceptance time among bookmaker_as_of_ts_ms values: the freshest returned bookmaker. Unlike as_of_ts_ms, bookmakers outside this response cannot advance it."},"stale_bookmakers":{"items":{"type":"string"},"type":"array","title":"Stale Bookmakers","description":"Returned bookmakers whose bookmaker_as_of_ts_ms is older than twice target_refresh_interval_seconds at response time. Empty when the target is unknown."},"target_refresh_interval_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Refresh Interval Seconds","description":"Current scheduler target for this event; source health and runtime load can add delay."},"ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttl Seconds"},"items":{"items":{"$ref":"#/components/schemas/OddLine"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"complete":{"type":"boolean","title":"Complete","description":"True when there are no more bookmaker-complete pages for this request.","default":true},"bookmakers_included":{"items":{"type":"string"},"type":"array","title":"Bookmakers Included","description":"Bookmakers whose complete matching line sets are included in this response."},"bookmaker_counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Bookmaker Counts","description":"Number of returned matching lines for each included bookmaker."},"excluded_bookmakers":{"items":{"$ref":"#/components/schemas/ExcludedBookmaker"},"type":"array","title":"Excluded Bookmakers","description":"Bookmakers this response leaves out: `not_entitled` when a `bookmakers` filter names a bookmaker the API key's plan or bookmaker grant does not include, `unknown_bookmaker` when the key is not a bookmaker in `/bookmakers`, and `stale` when a bookmaker's prices for this event are very stale (last accepted more than max(24 h, 20 x target_refresh_interval_seconds) ago, detail `age`; or only pre-match prices after kickoff, detail `started`; pass `include_stale=true` to get them). Empty when nothing was left out. Requested bookmakers that are available but have no current lines are not listed here; compare with `bookmakers_included`. The same list is sent in the `X-Excluded-Bookmakers` response header as `key:reason` pairs."},"resume":{"type":"string","title":"Resume","description":"Opaque stream resume token; pass it as 'since' to /stream."}},"type":"object","required":["event_id","items","resume"],"title":"OddsSnapshotResponse"},"OpportunityCounts":{"properties":{"positive_ev":{"type":"integer","title":"Positive Ev","default":0},"arbitrage":{"type":"integer","title":"Arbitrage","default":0},"middle":{"type":"integer","title":"Middle","default":0},"bonus_conversion":{"type":"integer","title":"Bonus Conversion","default":0}},"type":"object","title":"OpportunityCounts"},"PredictionContractBook":{"properties":{"contract_id":{"type":"string","title":"Contract Id"},"source_contract_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Contract Id"},"contract_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contract Name"},"outcome":{"type":"string","title":"Outcome"},"side":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Side"},"line":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line"},"player_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Player Name"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"probability_bids":{"items":{"$ref":"#/components/schemas/PredictionPriceLevel"},"type":"array","title":"Probability Bids"},"probability_asks":{"items":{"$ref":"#/components/schemas/PredictionPriceLevel"},"type":"array","title":"Probability Asks"},"best_bid_probability":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Bid Probability"},"best_bid_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Bid Size"},"best_ask_probability":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Ask Probability"},"best_ask_size":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Ask Size"},"last_trade_probability":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Last Trade Probability"},"gross_decimal_odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gross Decimal Odds"},"fee_adjusted_decimal_odds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fee Adjusted Decimal Odds"},"estimated_fee_per_contract":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Estimated Fee Per Contract"},"projection_eligible":{"type":"boolean","title":"Projection Eligible","default":false}},"type":"object","required":["contract_id","outcome"],"title":"PredictionContractBook"},"PredictionOrderBookItem":{"properties":{"id":{"type":"string","title":"Id"},"event_id":{"type":"string","title":"Event Id"},"provider":{"type":"string","title":"Provider"},"provider_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Event Id"},"provider_market_id":{"type":"string","title":"Provider Market Id"},"market_key":{"type":"string","title":"Market Key"},"market_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Name"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"bet_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bet Type"},"period":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Period"},"period_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Str"},"metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metric"},"player_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Player Name"},"home_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Home Team"},"away_team":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Away Team"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"in_play":{"type":"boolean","title":"In Play","default":false},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"size_unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Size Unit"},"total_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Volume"},"total_liquidity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Liquidity"},"fee_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fee Model"},"fee_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fee Rate"},"fee_multiplier":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fee Multiplier"},"fee_exponent":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fee Exponent"},"fee_estimated":{"type":"boolean","title":"Fee Estimated","default":true},"source_ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ts"},"observed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observed At"},"contracts":{"items":{"$ref":"#/components/schemas/PredictionContractBook"},"type":"array","title":"Contracts"}},"type":"object","required":["id","event_id","provider","provider_market_id","market_key","period"],"title":"PredictionOrderBookItem"},"PredictionOrderBookSnapshotResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"As Of Ts Ms"},"ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttl Seconds"},"items":{"items":{"$ref":"#/components/schemas/PredictionOrderBookItem"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"resume":{"type":"string","title":"Resume","description":"Redis stream ID to resume from; pass as 'since' to /stream."}},"type":"object","required":["event_id","resume"],"title":"PredictionOrderBookSnapshotResponse"},"PredictionPriceLevel":{"properties":{"price":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Price"},"size":{"type":"number","minimum":0.0,"title":"Size"}},"type":"object","required":["price","size"],"title":"PredictionPriceLevel"},"PublicStatusComponent":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"latency_source":{"type":"string","title":"Latency Source","default":"http"},"metrics":{"$ref":"#/components/schemas/PublicStatusMetrics"}},"type":"object","required":["id","name","status"],"title":"PublicStatusComponent"},"PublicStatusMetrics":{"properties":{"uptime_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uptime Pct"},"p50_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P50 Ms"},"p95_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P95 Ms"},"p99_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P99 Ms"},"error_rate_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Error Rate Pct"}},"type":"object","title":"PublicStatusMetrics"},"PublicStatusRateLimits":{"properties":{"status":{"type":"string","title":"Status"},"throttled_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Throttled Pct"}},"type":"object","required":["status"],"title":"PublicStatusRateLimits"},"PublicStatusResponse":{"properties":{"status":{"type":"string","title":"Status"},"as_of":{"type":"string","title":"As Of"},"window_seconds":{"type":"integer","title":"Window Seconds"},"components":{"items":{"$ref":"#/components/schemas/PublicStatusComponent"},"type":"array","title":"Components"},"rate_limits":{"$ref":"#/components/schemas/PublicStatusRateLimits"},"source":{"$ref":"#/components/schemas/PublicStatusSource"},"recent_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recent Status"},"recent_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Recent Window Seconds"},"recent_components":{"items":{"$ref":"#/components/schemas/PublicStatusComponent"},"type":"array","title":"Recent Components"},"recent_rate_limits":{"anyOf":[{"$ref":"#/components/schemas/PublicStatusRateLimits"},{"type":"null"}]}},"type":"object","required":["status","as_of","window_seconds","rate_limits","source"],"title":"PublicStatusResponse"},"PublicStatusSource":{"properties":{"fresh":{"type":"boolean","title":"Fresh"},"age_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Age Seconds"}},"type":"object","required":["fresh"],"title":"PublicStatusSource"},"RacingDividend":{"properties":{"bet_type":{"type":"string","enum":["WIN","PLACE"],"title":"Bet Type"},"runner_number":{"type":"string","maxLength":8,"minLength":1,"title":"Runner Number"},"product":{"type":"string","maxLength":80,"minLength":1,"title":"Product","description":"Source-declared payout product; never a closing fixed price."},"pool":{"type":"string","maxLength":80,"minLength":1,"title":"Pool"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*(?:\\d{0,10}|(?=[\\d.]{1,15}0*$)\\d{0,10}\\.\\d{0,4}0*$)","title":"Amount"},"unit_stake":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*(?:\\d{0,4}|(?=[\\d.]{1,9}0*$)\\d{0,4}\\.\\d{0,4}0*$)","title":"Unit Stake"},"currency":{"type":"string","const":"AUD","title":"Currency","default":"AUD"}},"additionalProperties":false,"type":"object","required":["bet_type","runner_number","product","pool","amount","unit_stake"],"title":"RacingDividend"},"RacingEventDetail":{"properties":{"event_id":{"type":"string","title":"Event Id"},"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["event_id","data"],"title":"RacingEventDetail"},"RacingEventListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RacingEventSummary"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["count"],"title":"RacingEventListResponse"},"RacingEventSummary":{"properties":{"event_id":{"type":"string","title":"Event Id","description":"Canonical racing event identifier (raceID)."},"race_start_time":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Race Start Time","description":"Unix seconds."},"race_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race Type"},"race_venue":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race Venue"},"race_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race Number"},"race_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race State"},"race_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race Country"},"race_distance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Race Distance"},"active_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Active Runners","description":"Best available active-runner count after known scratchings."},"total_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Runners","description":"Declared field size before known scratchings, when available."},"scratched_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scratched Runners","description":"Known scratched/removed runner count."},"runner_count_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Runner Count Source","description":"Bookmaker or schedule source used for the runner count."},"runner_count_updated_at_ts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Runner Count Updated At Ts","description":"Runner-count source time in Unix seconds."},"runner_count_complete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Runner Count Complete","description":"True only when the source declares state for the complete field."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Event lifecycle status. An open event can already have early bookmaker odds; fetching denotes active near-jump collection. Distinct from bookmaker snapshot statuses such as ok. Omit the status filter when discovering early races."},"bookmaker_links":{"additionalProperties":true,"type":"object","title":"Bookmaker Links"},"scrapping_links":{"additionalProperties":true,"type":"object","title":"Scrapping Links"},"last_capture":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Last Capture","description":"Unix seconds."}},"type":"object","required":["event_id"],"title":"RacingEventSummary"},"RacingOddsBookmakerSnapshot":{"properties":{"bookmaker_name":{"type":"string","title":"Bookmaker Name"},"race_id":{"type":"string","title":"Race Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Bookmaker snapshot status, distinct from event status. Early prices use ok; near-jump collection uses fetching. Both may contain valid prices; do not require fetching to read odds. Other statuses may occur; inspect runner prices and timestamps."},"total_matched":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Matched","description":"Cumulative amount matched on the exchange WIN market in the source feed's currency. Betfair racing is currently requested in AUD."},"updated_at_ts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Updated At Ts","description":"Snapshot update time in Unix seconds. On compact clients, request include_source=true to include it."},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"Bookmaker-specific payload, omitted when include_raw_payload=false (the compact default). Sportsbet WIN prices use payload.horse_data[].odds, with horse_name and number; payload.runners[].win_odds is not a universal raw schema.","examples":[{"horse_data":[{"horse_name":"Example Runner","number":"1","odds":3.4}],"status":"ok"}]},"racecard":{"type":"object","description":"Complete source-declared field, independent of prices, including scratched and unpriced runners. Contains source, observed_at_ts, field_complete, connections_complete and runners. Missing connections remain absent. Field completeness does not imply all jockeys/trainers or prices have been published."},"runners":{"items":{"properties":{"runner_number":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"null"}],"title":"Runner Number"},"runner_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Runner Name"},"win_odds":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Win Odds","description":"Decimal WIN price, when supplied."},"place_odds":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Place Odds","description":"Decimal PLACE price, when supplied."},"jockey_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jockey Name"},"trainer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trainer Name"},"selection_id":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"null"}],"title":"Selection Id"},"runner_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Runner Status"},"is_scratched":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Scratched"},"removal_date":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"},{"type":"null"}],"title":"Removal Date"},"adjustment_factor":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Adjustment Factor"},"traded_volume":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Traded Volume","description":"Cumulative exchange-matched amount for this runner in the source feed's currency. Betfair racing is currently requested in AUD."}},"type":"object","title":"RacingOddsRunner","description":"Compact runner fields; absent source values are omitted from responses."},"type":"array","description":"Compact prices at items[].runners[].win_odds. Present for priced runners on compact clients, or when include_raw_payload=false. Runners without WIN or PLACE prices are omitted."},"bookmaker_link":{"type":"string","description":"Source race URL, when available and include_links=true. Independent of include_raw_payload; also applies to stream snapshots."}},"type":"object","required":["bookmaker_name","race_id"],"title":"RacingOddsBookmakerSnapshot"},"RacingOddsSnapshotResponse":{"properties":{"event_id":{"type":"string","title":"Event Id"},"as_of_ts_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"As Of Ts Ms"},"ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttl Seconds"},"active_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Active Runners"},"total_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Runners"},"scratched_runners":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scratched Runners"},"runner_count_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Runner Count Source"},"runner_count_updated_at_ts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Runner Count Updated At Ts"},"runner_count_complete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Runner Count Complete"},"items":{"items":{"$ref":"#/components/schemas/RacingOddsBookmakerSnapshot"},"type":"array","title":"Items"},"resume":{"type":"string","title":"Resume","description":"Redis stream ID to resume from; pass as 'since' to /stream."}},"type":"object","required":["event_id","resume"],"title":"RacingOddsSnapshotResponse"},"RacingPlacing":{"properties":{"runner_number":{"type":"string","maxLength":8,"minLength":1,"title":"Runner Number"},"runner_name":{"type":"string","maxLength":160,"minLength":1,"title":"Runner Name"},"position":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Position"}},"additionalProperties":false,"type":"object","required":["runner_number","runner_name","position"],"title":"RacingPlacing"},"RacingResult":{"properties":{"event_id":{"type":"string","maxLength":200,"minLength":1,"pattern":"^[A-Za-z0-9_.:-]+$","title":"Event Id"},"source":{"type":"string","const":"sportsbet","title":"Source"},"observed_at_ts":{"type":"integer","exclusiveMinimum":0.0,"title":"Observed At Ts"},"status":{"type":"string","enum":["provisional","official","abandoned"],"title":"Status"},"placings":{"items":{"$ref":"#/components/schemas/RacingPlacing"},"type":"array","maxItems":100,"title":"Placings"},"scratchings":{"items":{"$ref":"#/components/schemas/RacingScratching"},"type":"array","maxItems":100,"title":"Scratchings"},"dividends":{"items":{"$ref":"#/components/schemas/RacingDividend"},"type":"array","maxItems":200,"title":"Dividends"},"dividends_status":{"type":"string","enum":["pending","available","not_applicable"],"title":"Dividends Status","default":"pending"},"revision":{"type":"integer","minimum":1.0,"title":"Revision"},"updated_at_ts":{"type":"integer","exclusiveMinimum":0.0,"title":"Updated At Ts"}},"additionalProperties":false,"type":"object","required":["event_id","source","observed_at_ts","status","revision","updated_at_ts"],"title":"RacingResult"},"RacingResultItem":{"properties":{"event_id":{"type":"string","title":"Event Id"},"status":{"type":"string","enum":["available","pending"],"title":"Status"},"result":{"anyOf":[{"$ref":"#/components/schemas/RacingResult"},{"type":"null"}]}},"type":"object","required":["event_id","status"],"title":"RacingResultItem"},"RacingResultsListRequest":{"properties":{"event_ids":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Event Ids"}},"type":"object","required":["event_ids"],"title":"RacingResultsListRequest"},"RacingResultsListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RacingResultItem"},"type":"array","title":"Items"}},"type":"object","title":"RacingResultsListResponse"},"RacingScratching":{"properties":{"runner_number":{"type":"string","maxLength":8,"minLength":1,"title":"Runner Number"},"runner_name":{"type":"string","maxLength":160,"minLength":1,"title":"Runner Name"}},"additionalProperties":false,"type":"object","required":["runner_number","runner_name"],"title":"RacingScratching"},"ResultItem":{"properties":{"event_id":{"type":"string","title":"Event Id"},"status":{"type":"string","title":"Status","description":"available|pending"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"}},"type":"object","required":["event_id","status"],"title":"ResultItem"},"TennisScoreSubscription":{"properties":{"websocket_url":{"type":"string","title":"Websocket Url"},"command":{"additionalProperties":true,"type":"object","title":"Command"},"max_events_per_connection":{"type":"integer","title":"Max Events Per Connection"}},"type":"object","required":["websocket_url","command","max_events_per_connection"],"title":"TennisScoreSubscription"},"WidgetBookmakerOdds":{"properties":{"label":{"type":"string","title":"Label"},"selections":{"items":{"$ref":"#/components/schemas/WidgetSelectionPrice"},"type":"array","title":"Selections"}},"type":"object","required":["label"],"title":"WidgetBookmakerOdds"},"WidgetEvent":{"properties":{"league":{"type":"string","title":"League"},"event_name":{"type":"string","title":"Event Name"},"start_time":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Time"},"last_updated":{"type":"string","title":"Last Updated"},"markets":{"items":{"$ref":"#/components/schemas/WidgetMarket"},"type":"array","title":"Markets"},"event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"odds_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Odds Mode"},"captured_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Captured At"},"bookmaker_captured_at":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Bookmaker Captured At"},"capture_kind":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Capture Kind"},"event_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State"},"event_state_certainty":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State Certainty"}},"type":"object","required":["league","event_name","last_updated"],"title":"WidgetEvent"},"WidgetMarket":{"properties":{"market":{"type":"string","title":"Market"},"bookmakers":{"items":{"$ref":"#/components/schemas/WidgetBookmakerOdds"},"type":"array","title":"Bookmakers"}},"type":"object","required":["market"],"title":"WidgetMarket"},"WidgetOddsTickerResponse":{"properties":{"league":{"type":"string","title":"League"},"widget_id":{"type":"string","title":"Widget Id"},"last_updated":{"type":"string","title":"Last Updated"},"events":{"items":{"$ref":"#/components/schemas/WidgetEvent"},"type":"array","title":"Events"},"event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"odds_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Odds Mode"},"event_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event State"},"empty_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Empty Reason"}},"type":"object","required":["league","widget_id","last_updated"],"title":"WidgetOddsTickerResponse"},"WidgetSelectionPrice":{"properties":{"selection":{"type":"string","title":"Selection"},"price":{"type":"number","title":"Price"}},"type":"object","required":["selection","price"],"title":"WidgetSelectionPrice"},"TennisScore":{"properties":{"sport":{"const":"tennis","title":"Sport","type":"string"},"provider":{"const":"betfair","title":"Provider","type":"string"},"home":{"$ref":"#/components/schemas/TennisScoreParticipant"},"away":{"$ref":"#/components/schemas/TennisScoreParticipant"},"current_set":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current Set"},"current_game":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current Game"},"match_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Status"},"tie_break":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Tie Break"},"received_at":{"description":"Odds API receipt timestamp, not source time.","title":"Received At","type":"string"},"source_timestamp":{"default":null,"title":"Source Timestamp","type":"null"},"source_timestamp_available":{"const":false,"default":false,"title":"Source Timestamp Available","type":"boolean"}},"required":["sport","provider","home","away","current_set","current_game","match_status","tie_break","received_at"],"title":"TennisScore","type":"object"},"TennisScoreFreshness":{"properties":{"state":{"enum":["live","stale"],"title":"State","type":"string"},"age_ms":{"title":"Age Ms","type":"integer"},"poll_interval_ms":{"title":"Poll Interval Ms","type":"integer"}},"required":["state","age_ms","poll_interval_ms"],"title":"TennisScoreFreshness","type":"object"},"TennisScoreParticipant":{"properties":{"name":{"title":"Name","type":"string"},"sets":{"minimum":0,"title":"Sets","type":"integer"},"games":{"minimum":0,"title":"Games","type":"integer"},"points":{"title":"Points","type":"string"},"is_serving":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Serving"},"game_sequence":{"items":{"type":"integer"},"title":"Game Sequence","type":"array"}},"required":["name","sets","games","points","is_serving","game_sequence"],"title":"TennisScoreParticipant","type":"object"},"TennisScoreMessage":{"properties":{"type":{"enum":["image","delta"],"title":"Type","type":"string"},"event_id":{"title":"Event Id","type":"string"},"stream_id":{"description":"Process-session ID that scopes sequence values.","pattern":"^[0-9a-f]{32}$","title":"Stream Id","type":"string"},"sequence":{"description":"Monotonic semantic revision within one stream_id.","minimum":1,"title":"Sequence","type":"integer"},"update_kind":{"description":"How this complete replacement relates to the last state delivered on this connection.","enum":["initial","advance","correction","reaffirmation","reset"],"title":"Update Kind","type":"string"},"score":{"$ref":"#/components/schemas/TennisScore"},"freshness":{"$ref":"#/components/schemas/TennisScoreFreshness"}},"required":["type","event_id","stream_id","sequence","update_kind","score","freshness"],"title":"TennisScoreMessage","type":"object"},"ErrorResponse":{"type":"object","required":["detail"],"properties":{"detail":{"description":"Human-readable error detail. FastAPI may return a string or a validation-error object.","oneOf":[{"type":"string"},{"type":"object"},{"type":"array","items":{"type":"object"}}]},"code":{"type":"string","description":"Optional stable error code when provided by the endpoint."},"request_id":{"type":"string","description":"Optional request identifier for support/debugging."}}},"RateLimitResponse":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"}],"description":"Rate-limit response. Retry after the window or reduce polling frequency."},"ExchangeOrderBookStreamDelta":{"properties":{"op":{"title":"Op","type":"string"},"orderbook":{"$ref":"#/components/schemas/ExchangeOrderBookItem"}},"required":["op","orderbook"],"title":"ExchangeOrderBookStreamDelta","type":"object"},"ExchangeOrderBookStreamEvent":{"properties":{"event_id":{"title":"Event Id","type":"string"},"resume":{"title":"Resume","type":"string"},"changes":{"items":{"$ref":"#/components/schemas/ExchangeOrderBookStreamDelta"},"title":"Changes","type":"array"}},"required":["event_id","resume","changes"],"title":"ExchangeOrderBookStreamEvent","type":"object"},"PredictionOrderBookStreamDelta":{"properties":{"op":{"title":"Op","type":"string"},"orderbook":{"$ref":"#/components/schemas/PredictionOrderBookItem"}},"required":["op","orderbook"],"title":"PredictionOrderBookStreamDelta","type":"object"},"PredictionOrderBookStreamEvent":{"properties":{"event_id":{"title":"Event Id","type":"string"},"resume":{"title":"Resume","type":"string"},"changes":{"items":{"$ref":"#/components/schemas/PredictionOrderBookStreamDelta"},"title":"Changes","type":"array"}},"required":["event_id","resume","changes"],"title":"PredictionOrderBookStreamEvent","type":"object"},"OddsStreamDelta":{"properties":{"op":{"title":"Op","type":"string"},"odd":{"$ref":"#/components/schemas/OddLine"}},"required":["op","odd"],"title":"OddsStreamDelta","type":"object"},"OddsStreamEvent":{"properties":{"event_id":{"title":"Event Id","type":"string"},"resume":{"title":"Resume","type":"string"},"changes":{"items":{"$ref":"#/components/schemas/OddsStreamDelta"},"title":"Changes","type":"array"},"snapshot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Snapshot Id"},"batch_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Batch Index"},"batch_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Batch Count"}},"required":["event_id","resume","changes"],"title":"OddsStreamEvent","type":"object"},"RacingOddsStreamDelta":{"properties":{"op":{"title":"Op","type":"string"},"bookmaker_name":{"title":"Bookmaker Name","type":"string"},"snapshot":{"anyOf":[{"$ref":"#/components/schemas/RacingOddsBookmakerSnapshot"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"default":null,"description":"Compact clients receive the documented bookmaker snapshot with runners and optional bookmaker_link. Non-compact clients with include_raw_payload=true receive a bookmaker-specific raw object directly here (Sportsbet: snapshot.horse_data[].odds and snapshot.raceID), without a payload wrapper. Absent for removals.","title":"Snapshot"}},"required":["op","bookmaker_name"],"title":"RacingOddsStreamDelta","type":"object"},"RacingOddsStreamEvent":{"properties":{"event_id":{"title":"Event Id","type":"string"},"resume":{"title":"Resume","type":"string"},"changes":{"items":{"$ref":"#/components/schemas/RacingOddsStreamDelta"},"title":"Changes","type":"array"}},"required":["event_id","resume","changes"],"title":"RacingOddsStreamEvent","type":"object"},"ApiRootResponse":{"type":"object","required":["name","version","openapi","reference"],"properties":{"name":{"type":"string","example":"Odds API"},"version":{"type":"string","example":"1.0.0"},"openapi":{"type":"string","example":"/v1/openapi.json"},"reference":{"type":"string","example":"/v1/reference"}}},"ApiIdentityResponse":{"type":"object","description":"Authenticated API identity and enabled product capabilities.","additionalProperties":true,"properties":{"method":{"type":"string","example":"api_key"},"client_id":{"type":"string","nullable":true},"capabilities":{"type":"object","additionalProperties":true},"membership_tier":{"type":"integer","nullable":true}}},"UsageResponse":{"type":"object","description":"Quota and usage counters for the API key. New odds-api.net plans report API credits; legacy keys may still expose request-count fields.","additionalProperties":true,"properties":{"period_start_utc":{"type":"string","nullable":true},"period_end_utc":{"type":"string","nullable":true},"plan":{"type":"string","nullable":true},"pricing_model":{"type":"string","nullable":true},"api_credits_used":{"type":"integer","nullable":true},"api_credits_limit":{"type":"integer","nullable":true},"used":{"type":"integer","nullable":true},"limit":{"type":"integer","nullable":true},"request_count":{"type":"integer","nullable":true},"request_limit":{"type":"integer","nullable":true},"stream_hours_used":{"type":"number","format":"double","nullable":true},"stream_hours_limit":{"type":"integer","nullable":true},"stream_logical_bytes_used":{"type":"integer","nullable":true},"stream_logical_bytes_limit":{"type":"integer","nullable":true},"stream_concurrent_units_used":{"type":"integer","nullable":true},"stream_concurrent_units_limit":{"type":"integer","nullable":true}}},"LimitsResponse":{"type":"object","required":["responses","sse"],"properties":{"responses":{"type":"object","required":["events_limit_max","odds_snapshot_limit_max","bets_snapshot_limit_max"],"properties":{"events_limit_max":{"type":"integer","example":1000},"odds_snapshot_limit_max":{"type":"integer","example":25000},"bets_snapshot_limit_max":{"type":"integer","example":20000}}},"sse":{"type":"object","required":["heartbeat_sec_min","heartbeat_sec_max","max_batch_default"],"properties":{"heartbeat_sec_min":{"type":"integer","example":5},"heartbeat_sec_max":{"type":"integer","example":120},"max_batch_default":{"type":"integer","example":500}}},"streams":{"type":"object","additionalProperties":true,"description":"Shared stream-hour, logical-byte, and concurrent-unit rules for API-key SSE and WebSocket connections."},"plan_id":{"type":"string","nullable":true},"pricing_model":{"type":"string","nullable":true},"billing_status":{"type":"string","nullable":true},"quotas":{"type":"object","additionalProperties":true},"entitlements":{"type":"object","additionalProperties":true},"add_ons":{"type":"object","additionalProperties":true},"usage_unit":{"type":"string","nullable":true,"example":"api_credits"},"overage_policy":{"type":"string","nullable":true,"example":"hard_cap"}}},"StringListResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"string"}}}},"LeagueDetail":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"Saudi Pro League"},"sport":{"type":"string","nullable":true,"example":"soccer"},"country_code":{"type":"string","nullable":true,"description":"ISO 3166-1 alpha-2, GB-ENG/GB-SCT/GB-WLS for UK nations, or INT for international competitions.","example":"SA"},"country":{"type":"string","nullable":true,"description":"Country name, or the region for INT competitions (for example `Europe`).","example":"Saudi Arabia"}}},"LeagueListResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"string"},"description":"Active league names (unchanged string list)."},"details":{"type":"array","items":{"$ref":"#/components/schemas/LeagueDetail"},"description":"One entry per active league and sport, with the league's country."}}},"BookmakerCatalogItem":{"type":"object","required":["bookmaker","country_codes"],"properties":{"bookmaker":{"type":"string","description":"Canonical bookmaker identifier accepted by bookmaker filters.","example":"bet365"},"country_codes":{"type":"array","items":{"type":"string"},"description":"Country codes where this bookmaker is active, for example `AU` or `UK`.","example":["AU","UK"]},"source_bookmaker":{"type":"string","nullable":true,"description":"Canonical source bookmaker when this bookmaker reuses another bookmaker's sports odds.","example":"betnation"}}},"BookmakerCatalogResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/BookmakerCatalogItem"}}}},"BookmakerCountryCatalogItem":{"type":"object","required":["country_code","bookmakers"],"properties":{"country_code":{"type":"string","example":"AU"},"country":{"type":"string","nullable":true,"example":"Australia"},"bookmakers":{"type":"array","items":{"type":"string"},"description":"Canonical bookmaker identifiers active for this country code."}}},"BookmakerCountriesCatalogResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/BookmakerCountryCatalogItem"}}}},"BetOpportunity":{"type":"object","description":"A normalized betting opportunity. Strategy-specific fields may be present.","additionalProperties":true,"properties":{"id":{"type":"string"},"strategy":{"type":"string","enum":["pos_ev","arbitrage","middles","freebets","pos_ev_special"]},"event_id":{"type":"string","nullable":true},"bookmaker_name":{"type":"string","nullable":true},"selection_key":{"type":"string","nullable":true},"odds":{"type":"number","nullable":true},"fair_odds":{"type":"number","nullable":true},"ev":{"type":"number","nullable":true},"ev_multiplicative_method":{"type":"number","nullable":true},"ev_additive_method":{"type":"number","nullable":true},"ev_power_method":{"type":"number","nullable":true},"ev_shin_method":{"type":"number","nullable":true}}},"BetsSnapshotResponse":{"type":"object","required":["resume","items"],"properties":{"resume":{"type":"string","description":"JSON string mapping each requested strategy to its stream resume ID."},"items":{"type":"array","items":{"$ref":"#/components/schemas/BetOpportunity"}}}},"BetsStreamDelta":{"type":"object","required":["strategy","op","id"],"properties":{"strategy":{"type":"string"},"op":{"type":"string","enum":["upsert","delete"]},"id":{"type":"string"},"doc":{"$ref":"#/components/schemas/BetOpportunity"}}},"BetsStreamEvent":{"type":"object","required":["resume","events"],"properties":{"resume":{"type":"string"},"events":{"type":"array","items":{"$ref":"#/components/schemas/BetsStreamDelta"}}}},"OddsHistoryStreamEvent":{"type":"object","required":["event_id","selection_key","resume","points"],"properties":{"event_id":{"type":"string"},"selection_key":{"type":"string"},"resume":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/OddsHistoryPoint"}}}},"RacingEventsStreamChange":{"type":"object","required":["op","event_id"],"properties":{"op":{"type":"string","enum":["upsert","remove"]},"event_id":{"type":"string"},"event":{"type":"object","nullable":true,"additionalProperties":true}}},"RacingEventsStreamEvent":{"type":"object","required":["resume","changes"],"properties":{"resume":{"type":"string"},"changes":{"type":"array","items":{"$ref":"#/components/schemas/RacingEventsStreamChange"}}}},"StreamHeartbeat":{"type":"object","description":"Heartbeat payload. All streams use it as a liveness signal; event-odds streams also include the latest event and bookmaker freshness metadata so a no-price-change capture is observable.","additionalProperties":false,"properties":{"event_id":{"type":"string","nullable":true},"resume":{"type":"string","nullable":true},"as_of_ts_ms":{"type":"integer","nullable":true},"snapshot_capture_ts_ms":{"type":"integer","nullable":true},"bookmaker_as_of_ts_ms":{"type":"object","additionalProperties":{"type":"integer"}},"oldest_bookmaker_as_of_ts_ms":{"type":"integer","nullable":true},"newest_bookmaker_as_of_ts_ms":{"type":"integer","nullable":true},"stale_bookmakers":{"type":"array","items":{"type":"string"}},"target_refresh_interval_seconds":{"type":"integer","nullable":true}}},"StreamResyncEvent":{"type":"object","description":"Sent when a resume token is no longer available and the client should reload the snapshot.","required":["reason"],"properties":{"event_id":{"type":"string","nullable":true},"selection_key":{"type":"string","nullable":true},"resume":{"type":"string","nullable":true},"reason":{"type":"string","example":"trimmed"},"snapshot_id":{"type":"string","nullable":true}}},"InPlayExchangeWebSocketMessage":{"type":"object","description":"Multiplexed in-play exchange WebSocket message.","required":["type"],"additionalProperties":true,"properties":{"type":{"type":"string","enum":["subscribed","unsubscribed","image","delta","heartbeat","pong","error","warming_timeout"]},"event_id":{"type":"string","nullable":true},"resume":{"type":"string","nullable":true},"origin":{"type":"string","enum":["cache","live"],"description":"Image only. cache: WagerWise's last-known book, sent on subscribe and possibly old. live: the first book from the live stream for this subscription."},"market_ids":{"type":"array","items":{"type":"string"}},"changes":{"type":"array","items":{"type":"object","additionalProperties":true}},"sync":{"type":"object","description":"Heartbeat only. Per subscribed market_id: synced_at (Betfair stream clock), sync_age_seconds, and in_sync (stream-confirmed current within 15 s). Heartbeats are otherwise connection liveness only.","additionalProperties":{"type":"object","properties":{"synced_at":{"type":"string","nullable":true},"sync_age_seconds":{"type":"number","nullable":true},"in_sync":{"type":"boolean"}}}}}}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Send your API key in this header on every request."}}},"tags":[{"name":"Start here","description":"API identity, base URL, authentication, and reference links."},{"name":"Status","description":"Buyer-facing API availability, latency, stream health, and rate-limit health."},{"name":"Account","description":"Current API identity, usage counters, and contract limits."},{"name":"Catalog","description":"Supported sports, leagues, bookmakers, and approximate market coverage."},{"name":"Widgets","description":"Public-safe embeddable widget feeds for approved API clients."},{"name":"Sports events","description":"Upcoming and live sports events plus event metadata."},{"name":"Sports odds","description":"Sports odds snapshots, line movement, Server-Sent Events, and WebSocket updates."},{"name":"Bulk history (beta)","description":"Period-based bulk downloads of recorded odds history as hourly compressed files. Beta; requires approval."},{"name":"Sports exchange","description":"Sports betting exchange order books with back/lay ladders, liquidity, and live updates."},{"name":"Prediction markets","description":"Event-linked prediction-market order books with probability ladders, liquidity, and live updates."},{"name":"Racing events","description":"Racing event discovery and live racing event updates."},{"name":"Racing odds","description":"Racing odds snapshots, home racing feeds, Server-Sent Events, and WebSocket updates."},{"name":"Betting opportunities","description":"Positive EV, arbitrage, middle, and bonus-bet opportunity feeds."},{"name":"Results","description":"Sports event result lookup."}],"servers":[{"url":"https://api.odds-api.net/v1","description":"Production V1 base URL. Set ODDS_API_BASE_URL to override it in SDKs and examples."}],"security":[{"ApiKeyAuth":[]}]}