# AI & LLM Integration - Documentation Export Source: https://docs.oddspapi.io/ai Download OddsPapi documentation for AI tools, LLMs, and offline use. Machine-readable exports in TXT and OpenAPI JSON formats for ChatGPT, Claude, and other AI assistants. ## Download * **Docs index:** [`/llms.txt`](/llms.txt) * **Full docs bundle:** [`/llms-full.txt`](/llms-full.txt) * **OpenAPI (REST reference):** [`/api-reference/openapi.json`](/api-reference/openapi.json) ## Recommended usage If your AI tool supports fetching URLs, give it: * `/llms-full.txt` (best for “read everything once”) * `/api-reference/openapi.json` (best for endpoint + schema accuracy) If your tool only supports copy/paste, open `/llms-full.txt` in the browser and paste the contents. ## Notes * `llms-full.txt` follows the same ordering as the site navigation. * WebSocket channels are documented in MDX; REST endpoints are in OpenAPI. *** ## 💬 Ask an AI Assistant Want to explore or ask questions about this page using your favorite AI? Click one of the links below — each one opens this page in the selected tool with a pre-filled prompt: * [Ask ChatGPT](https://chatgpt.com/?prompt=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+with+this+API.) * [Ask Claude](https://claude.ai/?prompt=Please+read+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+use+this+API.) * [Ask Perplexity](https://www.perplexity.ai/search?q=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt) * [Ask Gemini](https://gemini.google.com/app?query=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+use+this+API.) # API Authentication - How to Authenticate Requests Source: https://docs.oddspapi.io/api-reference/authentication Learn how to authenticate OddsPapi API requests using your API key. Simple query parameter authentication for all HTTP endpoints. All HTTP endpoints require an `apiKey`. You will only receive: 1. what you are requesting, filtered by 2. what you have access for ## How to authenticate Pass your key as a query parameter: ```bash theme={null} curl 'https://v5.oddspapi.io/en/bookmakers?apiKey=YOUR_KEY' ``` # Get Bookmakers Source: https://docs.oddspapi.io/api-reference/common/get-bookmakers api-reference/openapi.json get /bookmakers List bookmakers. Returns the bookmaker catalog available to the provided apiKey. Lookup mode: `bookmakers` (optional filter list) + `playerProps` (optional capability filter). # Get Currencies Source: https://docs.oddspapi.io/api-reference/common/get-currencies api-reference/openapi.json get /currencies List currencies and conversion values. Lookup mode: `currency` (optional filter). # Get Markets Source: https://docs.oddspapi.io/api-reference/common/get-markets api-reference/openapi.json get /markets List markets. Lookup mode: `marketIds` OR `sportId` OR `outcomeIds`. # Get Participants Source: https://docs.oddspapi.io/api-reference/common/get-participants api-reference/openapi.json get /participants List participants. Lookup mode: `participantIds` OR `sportId` OR `playerId`. # Get Players Source: https://docs.oddspapi.io/api-reference/common/get-players api-reference/openapi.json get /players List players. Lookup mode: `playerIds` OR `participantId` OR `sportId`. # Get Seasons Source: https://docs.oddspapi.io/api-reference/common/get-seasons api-reference/openapi.json get /seasons List seasons. Lookup mode: `seasonIds` OR `tournamentId`. # Get Sports Source: https://docs.oddspapi.io/api-reference/common/get-sports api-reference/openapi.json get /sports List sports. Lookup mode: `sportIds` (optional filter list). # Get Tournaments Source: https://docs.oddspapi.io/api-reference/common/get-tournaments api-reference/openapi.json get /tournaments List tournaments. Lookup mode: `sportId` OR `tournamentIds`. Default: if neither is provided, the API uses `sportId=11`. # Core Concepts - IDs, Data Models & Best Practices Source: https://docs.oddspapi.io/api-reference/concepts Understand OddsPapi data models: fixture IDs, market IDs, odds identifiers, entity relationships, timestamps, and implementation best practices for arbitrage detection. This page explains the core concepts used throughout the Odds API: how IDs are constructed, how entities relate to each other, how timestamps are used, and how to design reliable client-side storage. *** ## Language prefix All endpoints are prefixed with a language code: * `/en/...` * `/de/...` * `/fr/...` Translated fields (for example names) follow the prefix language when available. Identifiers (`sportId`, `fixtureId`, etc.) are language-independent. *** ## Sports, tournaments, seasons ### sportId * Integer. * The **first two digits** embedded into several downstream IDs. * Discover via `/sports`. ### tournamentId * Integer. * Belongs to exactly one sport. * Discover via `/tournaments`. ### seasonId * Integer. * Belongs to exactly one tournament. * Discover via `/seasons`. *** ## Markets and outcomes ### Relationship between `marketId` and `outcomeId` Markets and outcomes are tightly coupled by design: * A **market** represents a complete betting market (for example moneyline, 1x2, totals). * A **market contains multiple outcomes**. * **All outcomes that belong to the same market share the same `marketId`.** * **The first `outcomeId` of a market is always equal to the `marketId`.** This makes it possible to determine which outcomes belong to which market **without additional metadata**. ### ID structure Both `marketId` and `outcomeId` are integers constructed as: ``` {sportId (2 digits)} + {incrementing number} ``` Examples: * `11xxxx` → basketball market or outcome * `14xxxx` → American football market or outcome This design provides: * Unlimited markets and outcomes per sport * Fast grouping by sport * Immediate visibility of market relationships ### Why `marketId` matters (arbitrage & modeling) All outcomes under a single `marketId` together represent a **complete probability space**. This makes `marketId` especially useful for: * Arbitrage detection * Overround / margin calculations * Probability normalization * Market completeness checks **Recommendation:** If you perform arbitrage or pricing logic, always group odds by `marketId`. *** ## Participants and players ### participantId * Integer. * Represents teams or competitors in fixtures. * Discover via `/participants`. ### playerId * Integer. * Used for player proposition markets. * `playerId = 0` typically represents a non-player market. * Discover via `/players`. *** ## Fixture IDs ### fixtureId structure `fixtureId` is a **string** that encodes multiple pieces of information: ``` {providerSlug}{sportId}{tournamentId}{providerFixtureId} ``` Conceptual example: ``` id1100013262926199 ``` Where: * `id` → provider identifier / short slug * `11` → sportId (2 digits) * `000132` → tournamentId (6 digits) * `62926199` → provider’s native fixture ID ### Why this matters From the `fixtureId` alone, you can infer: * The sport * The tournament * The upstream provider * Global uniqueness This makes logging, debugging, analytics, and cross-system correlation simpler and more reliable. *** ## Future IDs ### futureId structure `futureId` follows a similar principle: ``` {providerSlug}{sportId}{seasonId}{marketId} ``` This encodes: * Provider * Sport * Season * Market Like `fixtureId`, this makes futures: * Globally unique * Self-describing * Easy to debug and trace *** ## Odds identifiers ### Fixture odds keys For fixtures, a single price is uniquely identified by: ``` {fixtureId}:{bookmaker}:{outcomeId}:{playerId} ``` Example: ``` id1400003160574217:bet365:141:0 ``` This combination uniquely defines **one price**. ### Future odds IDs For futures, odds are uniquely identified by: ``` {futureId}:{bookmaker}:{outcomeId}:{participantId}:{playerId} ``` This fully specifies: * The future * The bookmaker * The outcome * The participant (when applicable) * The player (for props) ### Storage recommendation (important) We strongly recommend using these identifiers as **primary keys** in your storage: **Fixture odds:** ``` {fixtureId}:{bookmaker}:{outcomeId}:{playerId} ``` **Future odds:** ``` {futureId}:{bookmaker}:{outcomeId}:{participantId}:{playerId} ``` This guarantees: * No duplicates * Simple updates * Efficient time-series storage * Easy reconciliation across snapshots and backfills *** ## Timestamps (seconds vs milliseconds) This API intentionally uses **both epoch seconds and epoch milliseconds**, depending on context. ### Epoch seconds (UTC) Used for scheduled or coarse-grained time values: * `startTime` * `startTimeFrom` * `startTimeTo` ### Epoch milliseconds (UTC) Used for high-frequency price updates: * `changedAt` * Odds `since` filters for fixtures * Futures odds `createdAt` ### Recommendation * Store timestamps as integers. * Do not assume milliseconds where seconds are documented (or vice versa). * Normalize internally only if needed. *** ## Implementation recommendations ### Server Location Matters To achieve the lowest latency for realtime updates: * The **fastest delivery regions** are Central Europe (recommended) and US East. * For best performance, deploy your backend **in the same datacenters we use**, such as: * [Netcup](https://www.netcup.com/en/?ref=294017) * [Hetzner](https://www.hetzner.com/cloud) * If you're building **prediction markets or models sensitive to latency**, consider: * Deploying in **Austria (AT)** via Netcup, or * Using **AWS eu-west-1** (Ireland) > ⚡ Servers colocated near our streaming infrastructure receive updates faster and with fewer hops. ### Snapshot + realtime pattern A reliable integration pattern: 1. Fetch **HTTP snapshot** (fixtures, odds, or futures) 2. Subscribe to **WebSocket** for realtime updates 3. If WebSocket signals `snapshot_required`: * Re-fetch HTTP snapshot * Resume realtime stream ### Efficient backfills * Use `since` parameters where available * Avoid full historical fetches unless required * Store odds keyed by their odds identifiers for deduplication ### Rate limit handling * Read `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` * On HTTP 429, respect `Retry-After` and back off *** ## Summary This API is designed so that: * IDs are **self-describing** * Relationships are **derivable without joins** * Odds identifiers are **globally unique** * Arbitrage and storage logic are **straightforward and robust** Modeling your system around these principles will result in a fast, maintainable, and future-proof integration. # API Error Codes - HTTP Status Codes & Error Handling Source: https://docs.oddspapi.io/api-reference/errors Complete guide to OddsPapi API error responses. HTTP status codes, error formats, rate limit headers, and troubleshooting common error causes. ## Error Format Most error responses return a JSON object like: ```json theme={null} { "error": 401, "message": "invalid apiKey", "code": "invalid_api_key" } ``` | Field | Type | Description | | --------- | ------- | ---------------------------- | | `error` | integer | HTTP status code | | `message` | string | Human-readable description | | `code` | string | Machine-readable reason code | *** ## Rate Limit Headers All endpoints protected by the rate limiter return these headers: | Header | Description | | ----------------------- | ---------------------------------------- | | `X-RateLimit-Limit` | Requests allowed per window (per apiKey) | | `X-RateLimit-Remaining` | Requests left in the current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | If you hit the limit (`429`), you also receive: | Header | Description | | ------------- | ------------------------------- | | `Retry-After` | Seconds to wait before retrying | *** ## Common Error Responses ### 400 — Bad Request ```json theme={null} { "error": 400, "message": "Invalid filters.", "code": "invalid_filters" } ``` Used for syntactically valid requests with invalid parameters. *** ### 401 — Unauthorized **Missing or invalid `apiKey`.** ```json theme={null} { "error": 401, "message": "missing apiKey", "code": "missing_api_key" } ``` ```json theme={null} { "error": 401, "message": "invalid apiKey", "code": "invalid_api_key" } ``` *** ### 403 — Forbidden **Valid API key, but no access to this channel or feature.** ```json theme={null} { "error": 403, "message": "Access denied: apiKey is not allowed to access this endpoint.", "code": "channel_not_allowed" } ``` *** ### 422 — Validation Error Usually returned by FastAPI’s internal validation. ```json theme={null} { "error": 422, "message": "Validation error", "code": "validation_error", "details": [ { "loc": ["query", "fixtureId"], "msg": "Field required", "type": "missing" } ] } ``` *** ### 429 — Rate Limit Exceeded Triggered when request volume exceeds limits per apiKey. ```json theme={null} { "error": 429, "message": "rate limit exceeded", "code": "rate_limited", "limit": 30, "windowSec": 1, "retryAfterSec": 1, "endpoint": "/fixtures/odds", "method": "GET" } ``` Headers: * `Retry-After: 1` * `X-RateLimit-Limit: 30` * `X-RateLimit-Remaining: 0` * `X-RateLimit-Reset: 1700000000` *** ### 503 — Service Unavailable If internal systems (e.g. rate limiter) are unavailable: ```json theme={null} { "error": 503, "message": "rate limiter unavailable", "code": "rate_limiter_error" } ``` ## Notes * `code` is stable and suitable for programmatic handling. * `message` may change (but is designed to help developers). * Most endpoints return `429` if rate-limited — check your headers. * FastAPI validation errors are always returned as `422`. *** # Fixtures Filtered Source: https://docs.oddspapi.io/api-reference/fixtures/fixtures-filtered api-reference/openapi.json get /fixtures List fixtures. Lookup mode: `fixtureIds` OR filters (`sportId`, `tournamentId`, `statusId`, optional time range). If `bookmakers` is present, bookmaker meta is included and results may be filtered by mapping availability. # Fixtures Live Source: https://docs.oddspapi.io/api-reference/fixtures/fixtures-live api-reference/openapi.json get /fixtures/live List live fixtures. Lookup mode: optional filters (`bookmakers`, `sportId`, `tournamentId`). # Fixtures Today Source: https://docs.oddspapi.io/api-reference/fixtures/fixtures-today api-reference/openapi.json get /fixtures/today List today's fixtures. Lookup mode: optional filters (`bookmakers`, `sportId`, `tournamentId`). # Fixture Odds Source: https://docs.oddspapi.io/api-reference/fixturesodds/fixture-odds api-reference/openapi.json get /fixtures/odds Get current odds for a fixture. Lookup mode: required `fixtureId` + optional `bookmakers`, optional filtering flags. If `since` is provided, returns odds updates with `changedAt >= since`. # Fixture Odds CLV Source: https://docs.oddspapi.io/api-reference/fixturesodds/fixture-odds-clv api-reference/openapi.json get /fixtures/odds/clv Get opening vs closing line values (OLV/CLV) for a fixture. Lookup mode: required `fixtureId` + optional `bookmakers` OR optional `oddsIds`. # Fixture Odds Historical Source: https://docs.oddspapi.io/api-reference/fixturesodds/fixture-odds-historical api-reference/openapi.json get /fixtures/odds/historical Get historical odds timeline for a fixture. Lookup mode: required `fixtureId` + (`bookmaker` required when `oddsIds` is not provided) OR `oddsIds`. # Fixtures Odds Main Source: https://docs.oddspapi.io/api-reference/fixturesodds/fixtures-odds-main api-reference/openapi.json get /fixtures/odds/main Get current main odds for multiple fixtures. Lookup mode: provide exactly one of: - `tournamentId` (recommended) - `fixtureIds` (fast path) If `since` is provided, returns odds updates with `changedAt >= since`. # Futures Filtered Source: https://docs.oddspapi.io/api-reference/futures/futures-filtered api-reference/openapi.json get /futures List futures. Lookup mode: `futureIds` OR `sportId` OR `tournamentId` (at least one). # Futures Live Source: https://docs.oddspapi.io/api-reference/futures/futures-live api-reference/openapi.json get /futures/live List live futures. Lookup mode: optional `sportId` / `tournamentId` filters. # Future Odds Source: https://docs.oddspapi.io/api-reference/futuresodds/future-odds api-reference/openapi.json get /futures/odds Get latest odds for a future. Lookup mode: required `futureId` + optional filters (`bookmakers`, `since`, `mainLines`, `includeFuture`). # Future Odds CLV Source: https://docs.oddspapi.io/api-reference/futuresodds/future-odds-clv api-reference/openapi.json get /futures/odds/clv Get OLV and CLV for a future’s odds. Lookup mode: required `futureId` + optional `bookmakers` OR optional `oddsIds`. # Future Odds Historical Source: https://docs.oddspapi.io/api-reference/futuresodds/future-odds-historical api-reference/openapi.json get /futures/odds/historical Get historical odds changes for a future. Lookup mode: required `futureId` + (`bookmakers` required when `oddsIds` is not provided) OR `oddsIds`. # Fixture Mapping Source: https://docs.oddspapi.io/api-reference/mapping/fixture-mapping api-reference/openapi.json get /fixtures/mapping List fixture mappings for external bookmakers. Lookup mode: `bookmaker` (optional) + `fixtureIds` OR `bookmakerFixtureIds`. # Future Mapping Source: https://docs.oddspapi.io/api-reference/mapping/future-mapping api-reference/openapi.json get /futures/mapping Map internal future IDs to bookmaker/provider future IDs. Lookup mode: required `bookmaker` + (`futureIds` OR `bookmakerFutureIds`). # Media Bookmaker Source: https://docs.oddspapi.io/api-reference/media/media-bookmaker api-reference/openapi.json get /media/bookmakers/{slug} Get bookmaker logo. Returns an HTTP redirect to the image asset. Response: 302 with `Location` header (final resource typically WebP). # Media Category Source: https://docs.oddspapi.io/api-reference/media/media-category api-reference/openapi.json get /media/categories/{category} Get category icon. Returns an HTTP redirect to the image asset. Response: 302 with `Location` header (final resource typically SVG). # Media Participant Source: https://docs.oddspapi.io/api-reference/media/media-participant api-reference/openapi.json get /media/participants/{participantId} Get participant image. Returns an HTTP redirect to the image asset. Response: 302 with `Location` header (final resource typically PNG). # Media Tournament Source: https://docs.oddspapi.io/api-reference/media/media-tournament api-reference/openapi.json get /media/tournaments/{tournamentId} Get tournament image. Returns an HTTP redirect to the image asset. Response: 302 with `Location` header (final resource typically PNG). # REST API Overview - HTTP Endpoints for Sports Data Source: https://docs.oddspapi.io/api-reference/overview OddsPapi REST API reference. HTTP endpoints for sports betting data snapshots, metadata retrieval, historical odds, and recovery workflows. Supports 8 languages. The HTTP API complements WebSockets by providing: * **Initial snapshots** (bootstrap your local state) * **Recovery** after `snapshot_required` * **Metadata** (sports, tournaments, bookmakers) * **Backfills** (historical odds / CLV) when replay is not possible If you only need realtime updates, WebSockets may be enough. ## Base URL & languages All endpoints are prefixed with a language code: * `https://v5.oddspapi.io/{lang}` Examples: * `https://v5.oddspapi.io/en/bookmakers` * `https://v5.oddspapi.io/de/sports` Available languages are: `en`, `es`, `fr`, `pt`, `de`, `it`, `ru`, `zh`. For simplicity, the documentation is written in English. ## Rate limits This API enforces request limits per `apiKey` per endpoint. See **Rate Limits** for the authoritative limits and endpoint groups: * `api-reference/rate-limits` *** ## 💬 Ask an AI Assistant Want to explore or ask questions about this page using your favorite AI? Click one of the links below — each one opens this page in the selected tool with a pre-filled prompt: * [Ask ChatGPT](https://chatgpt.com/?prompt=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+with+this+API.) * [Ask Claude](https://claude.ai/?prompt=Please+read+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+use+this+API.) * [Ask Perplexity](https://www.perplexity.ai/search?q=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt) * [Ask Gemini](https://gemini.google.com/app?query=Read+from+https%3A%2F%2Fdocs.oddspapi.io%2Fllms-full.txt+and+help+me+use+this+API.) # API Rate Limits - Request Quotas & Throttling Source: https://docs.oddspapi.io/api-reference/rate-limits OddsPapi API rate limits and quotas. Request limits per endpoint, rate limit headers, and best practices for handling 429 responses. Rate limits are counted **per `apiKey`** and by endpoint. ## Limits ### Odds endpoints (high-frequency) These endpoints allow higher throughput: * `GET /fixtures/odds` * `GET /fixtures/odds/main` * `GET /futures/odds` **Limit:** **10 requests / second** ### All other endpoints Everything else (metadata, fixtures list, mapping, settlements, historical, media redirects): **Limit:** **100 requests / minute** ## Rate limit headers Every response includes: * `X-RateLimit-Limit` * `X-RateLimit-Remaining` * `X-RateLimit-Reset` When limited (429), responses also include: * `Retry-After` ## What happens when you exceed limits You’ll receive: * **429** with `code: "rate_limited"` Example: ```json theme={null} { "error": 429, "message": "rate limit exceeded", "code": "rate_limited", "retryAfterSec": 1 } ``` # Fixture Settlement Source: https://docs.oddspapi.io/api-reference/settlement/fixture-settlement api-reference/openapi.json get /fixtures/settlement Get settlements for a fixture. Lookup mode: required `fixtureId` + optional `outcomeId`, optional `playerId`. # Future Settlement Source: https://docs.oddspapi.io/api-reference/settlement/future-settlement api-reference/openapi.json get /futures/settlement Get settlements for a future. Currently not available. # API Changelog - Updates, Features & Breaking Changes Source: https://docs.oddspapi.io/changelog/index OddsPapi API changelog. New features, improvements, bug fixes, and breaking changes. Track WebSocket and REST API updates for sports betting data integration. We continuously improve the Odds API. This page lists **new features**, **changes**, **fixes**, and **breaking changes**. All timestamps are UTC. If a change affects data shape or behavior, it will be marked as **Breaking**. *** ## 2025-12-12 ### ✨ Added * WebSocket **resume & replay** support using `entryId` cursors * New WebSocket channels: * `injuries` * `lineups` * `stats` * AsyncAPI 3.0 reference for WebSocket gateway ### 🔧 Improved * Reduced WebSocket latency for `odds` and `scores` * Better filtering for `sportIds`, `tournamentIds`, and `bookmakers` ### 🐛 Fixed * Fixed an issue where some `odds` updates were delivered without bookmaker gating * Fixed incorrect `live` flag on some fixtures during transitions *** ## 2025-11-28 ### ⚠️ Breaking * `odds.payload.odds` keys are now **always bookmaker-scoped** * Old clients expecting a flat structure must update ### ✨ Added * Support for `receiveType: "binary"` (MessagePack) * Added `entryId` to all update messages *** ## 2025-11-10 ### ✨ Added * Initial WebSocket gateway * Channels: * `fixtures` * `scores` * `odds` * `bookmakers` # OddsPapi - B2B Sports Betting Odds API Source: https://docs.oddspapi.io/index B2B low-latency realtime sports odds API. Stream live betting odds, fixtures, scores, lineups, injuries and statistics via WebSocket. REST API for snapshots and historical data. **B2B API** — OddsPapi is a business-to-business data service for licensed operators, trading firms, and enterprise platforms. Contact [contact@oddspapi.io](mailto:contact@oddspapi.io) for API access. ## What is OddsPapi? OddsPapi is a **B2B sports data API** providing **low-latency realtime data** including: * Fixtures & schedules * Live scores * Betting odds & markets * Lineups, injuries, stats, and more Built for **trading systems**, **sportsbooks**, **analytics**, and **media platforms**. Looking for an AI-friendly export? See **AI / Offline Export** or download `/llms-full.txt`. *** ## Get started Connect in minutes and stream realtime data. Subscribe to live odds, scores, and events. REST endpoints for snapshots and metadata. Track updates and breaking changes. # Quickstart Guide - Connect to Odds API in Minutes Source: https://docs.oddspapi.io/quickstart Get started with OddsPapi in minutes. Connect to the WebSocket gateway, authenticate with your API key, subscribe to channels, and stream realtime sports odds data. ## 1) Connect Gateway: * **ws**: `wss://v5.oddspapi.io/ws` ```js theme={null} import WebSocket from "ws"; const ws = new WebSocket("wss://v5.oddspapi.io/ws"); ws.on("open", () => { ws.send(JSON.stringify({ type: "login", apiKey: process.env.ODDS_API_KEY })); }); ws.on("message", (data) => { const msg = JSON.parse(data.toString()); console.log(msg.type ?? msg.channel, msg); }); ``` ```py theme={null} import json import os import websocket def on_open(ws): ws.send(json.dumps({ "type": "login", "apiKey": os.environ["ODDS_API_KEY"], })) def on_message(ws, message): msg = json.loads(message) print(msg.get("type") or msg.get("channel"), msg) ws = websocket.WebSocketApp( "wss://v5.oddspapi.io/ws", on_open=on_open, on_message=on_message, ) ws.run_forever() ``` ## 2) Minimal login ```json theme={null} { "type": "login", "apiKey": "YOUR_API_KEY" } ``` # JavaScript SDK - Node.js & Browser Client Source: https://docs.oddspapi.io/sdks/javascript Official OddsPapi JavaScript SDK for Node.js and browser. Connect to WebSocket API, stream realtime odds, and integrate sports betting data into your application. ## Status 🚧 **Coming soon** In the meantime, you can connect using native WebSockets: ```js theme={null} const ws = new WebSocket("wss://v5.oddspapi.io/ws"); ws.onopen = () => { ws.send(JSON.stringify({ type: "login", apiKey: "YOUR_API_KEY" })); }; ``` # Python SDK - Async WebSocket Client Source: https://docs.oddspapi.io/sdks/python Official OddsPapi Python SDK with async WebSocket support. Stream realtime sports betting odds and integrate with your Python trading systems and analytics. ## Status 🚧 **Coming soon** Example using `websockets`: ```python theme={null} import asyncio, json, websockets async def main(): async with websockets.connect("wss://v5.oddspapi.io/ws") as ws: await ws.send(json.dumps({ "type": "login", "apiKey": "YOUR_API_KEY" })) async for msg in ws: print(msg) asyncio.run(main()) ``` # WebSocket Authentication & Channel Filters Source: https://docs.oddspapi.io/websocket/auth Authenticate to OddsPapi WebSocket gateway and configure channel subscriptions. Filter by sports, tournaments, fixtures, and bookmakers for targeted data streaming. ## Login Message Connect and send a `login` message immediately: ```json theme={null} { "type": "login", "apiKey": "YOUR_API_KEY" } ``` **Rules:** * Must be the first message * Send within 10 seconds * Defines all subscriptions and filters *** ## Login with Channels and Filters ```json theme={null} { "type": "login", "apiKey": "YOUR_API_KEY", "receiveType": "binary", "channels": ["fixtures", "scores", "odds"], "sportIds": [10, 11, 12, 13], "tournamentIds": [35430, 39351], "fixtureIds": ["id1103543066138356", "id1103935163991375"], "bookmakers": ["stake"] } ``` *** ## Filter Mode | Field | Type | Description | | --------------- | ---------- | ------------------------------------------------ | | `channels` | `string[]` | Streams you want to receive. | | `sportIds` | `number[]` | Restrict to these sports. | | `tournamentIds` | `number[]` | Restrict to these tournaments. | | `fixtureIds` | `string[]` | Exact fixtures (fixture-scoped channels only). | | `futureIds` | `string[]` | Specific futures (future-scoped channels). | | `bookmakers` | `string[]` | Only receive these bookmakers (bookmaker-gated). | | `lang` | `string` | Translations (`en`, `de`, `fr`, etc.). | | `receiveType` | `string` | `"json"` or `"binary"`. | | `clientName` | `string` | Optional debug/metrics tag. | | `serverEpoch` | `string` | For resume. | | `lastSeenId` | `object` | `{ "": "" }` for resume. | > IDs like `fixtureId` and `futureId` are structured but should be treated as opaque in your logic. See [Concepts](/api-reference/concepts). *** ## Access: Live vs Pregame After login, the server tells you what you're allowed to receive: ```json theme={null} { "access": { "live": true, "pregame": false } } ``` These are determined by your `apiKey`, not client filters. *** ## Bookmaker-Gated Channels These channels require explicit bookmaker access: * `odds`, `bookmakers` * `oddsFutures`, `bookmakersFutures` You can restrict which bookmakers you receive: ```json theme={null} { "type": "login", "apiKey": "YOUR_API_KEY", "channels": ["odds", "bookmakers"], "receiveType": "binary", "bookmakers": ["stake", "pinnacle"] } ``` *** ## 🐍 Python Example ```python theme={null} import asyncio, json, websockets, msgpack WS_URL = "wss://v5.oddspapi.io/ws" API_KEY = "your-api-key" LOGIN = { "type": "login", "apiKey": API_KEY, "channels": ["fixtures", "scores", "odds"], "receiveType": "binary", "sportIds": [10, 11], "bookmakers": ["stake"], } async def main(): async with websockets.connect(WS_URL) as ws: await ws.send(json.dumps(LOGIN)) async for raw in ws: if isinstance(raw, str): print("CONTROL:", json.loads(raw)) else: msg = msgpack.unpackb(raw, raw=False) print("DATA:", msg.get("channel"), msg.get("entryId")) asyncio.run(main()) ``` # Bookmakers Channel - Sportsbook Status & Metadata Source: https://docs.oddspapi.io/websocket/channels/bookmakers Stream bookmaker status per fixture via WebSocket. Track which sportsbooks offer odds, detect stale/suspended markets, and monitor participant rotation flags. ## What it streams Metadata about which bookmakers are offering odds for a given fixture, and whether those odds are active, stale, suspended, or rotated. This stream complements the `odds` channel by giving you per-bookmaker status for each `fixtureId`. *** ## Routing * Entity key: `payload.fixtureId` * Filters: `sportIds`, `tournamentIds`, `fixtureIds`, `bookmakers` * Access: determined by your `apiKey` * Bookmaker-gated: ✅ Yes *** ## Payload structure | Field | Type | Description | | ------------------------------------- | ---------------- | ------------------------------------------------------------- | | `fixtureId` | `string` | The fixture this update applies to | | `bookmakers` | `object` | Map of `` → metadata object | | `bookmakers..bookmaker` | `string` | Bookmaker slug (e.g. `"stake"`, `"pinnacle"`) | | `bookmakers..bookmakerFixtureId` | `string \| null` | Optional bookmaker-side ID (may be a slug or compound string) | | `bookmakers..fixturePath` | `string \| null` | Optional bookmaker path or UI route (if supported) | | `bookmakers..hasOdds` | `boolean` | True if the bookmaker currently offers any odds | | `bookmakers..staleOdds` | `boolean` | True if odds haven’t updated recently | | `bookmakers..suspended` | `boolean` | True if this bookmaker's odds are suspended | | `bookmakers..participantsRotated` | `boolean` | True if participants have been rotated compared to baseline | | `bookmakers..meta` | `object \| null` | Optional metadata (bookmaker-specific) | | `bookmakers..updatedAt` | `string` | Last update timestamp (ISO 8601) | *** ## Example message ```json theme={null} { "channel": "bookmakers", "type": "UPDATE", "payload": { "fixtureId": "id1500026861811720", "bookmakers": { "stake": { "bookmaker": "stake", "bookmakerFixtureId": "46137681-avtomobilist-yekaterinburg-hc-lada-togliatti", "fixturePath": null, "hasOdds": true, "staleOdds": false, "suspended": false, "participantsRotated": false, "meta": null, "updatedAt": "2025-12-28T18:37:13.719926+00:00" } } }, "ts": 1766947033889, "entryId": "1766947033889-1" } ``` *** ## Notes * This channel helps identify inactive/stale bookmaker data before odds processing. * If a bookmaker is not present in `bookmakers`, you should assume **no current odds available** for that fixture. * `participantsRotated = true` usually means team sides were reversed or mapped inconsistently across books. # Bookmakers Futures Channel - Outright Market Status Source: https://docs.oddspapi.io/websocket/channels/bookmakersFutures Stream bookmaker availability for futures markets via WebSocket. Monitor which sportsbooks offer outright and season-long betting odds. ## What it streams Metadata per bookmaker describing whether a bookmaker offers odds for a given future, and whether those odds are active, stale, or suspended. This is the **future equivalent** of the `bookmakers` channel for fixtures. *** ## Routing * Entity key: `payload.futureId` * Filters: `sportIds`, `tournamentIds`, `futureIds`, `bookmakers` * Access: determined by your `apiKey` * Bookmaker-gated: ✅ Yes *** ## Payload structure | Field | Type | Description | | ----------------------------------- | ---------------- | -------------------------------------------------------- | | `futureId` | `string` | The future this update applies to | | `bookmakers` | `object` | Map of `` → metadata object | | `bookmakers..bookmaker` | `string` | Bookmaker slug (e.g. `"stake"`, `"pinnacle"`) | | `bookmakers..bookmakerFutureId` | `string \| null` | Optional bookmaker-side identifier for this future | | `bookmakers..futurePath` | `string \| null` | Optional deeplink or path to the future at the bookmaker | | `bookmakers..hasOdds` | `boolean` | True if the bookmaker currently offers odds | | `bookmakers..staleOdds` | `boolean` | True if odds haven’t been updated recently | | `bookmakers..suspended` | `boolean` | True if the bookmaker has suspended this future | | `bookmakers..meta` | `object \| null` | Optional bookmaker-specific metadata | | `bookmakers..updatedAt` | `string` | Last update timestamp (ISO 8601) | *** ## Example message ```json theme={null} { "channel": "bookmakersFutures", "type": "UPDATE", "payload": { "futureId": "id11028543137888", "bookmakers": { "stake": { "bookmaker": "stake", "bookmakerFutureId": "285431-nbl-new-zealand", "futurePath": null, "hasOdds": true, "staleOdds": false, "suspended": false, "meta": null, "updatedAt": "2025-12-28T18:37:13.719926+00:00" } } }, "ts": 1766947033889, "entryId": "1766947033889-501" } ``` *** ## Notes * Odds data itself is streamed via **`oddsFutures`** * If a bookmaker is missing from `bookmakers`, assume **no current odds** * Use this channel to: * detect stale or suspended futures * decide when to ignore or invalidate `oddsFutures` data * Semantics are intentionally identical to `bookmakers` (fixture-level), just scoped to `futureId` # Currencies Channel - Exchange Rates & Crypto Prices Source: https://docs.oddspapi.io/websocket/channels/currencies Stream realtime currency exchange rates via WebSocket. Fiat and cryptocurrency pricing data including BTC, ETH, and major tokens for odds conversion. ## What it streams Currency/ticker exchange values (vs a reference currency) for fiat and crypto. This is a **global channel** — it is not scoped to any fixture or future. *** ## Routing * Channel: `currencies` (global) * Filters: ❌ ignored * Access: allowed for all keys (unless specifically disabled) *** ## Payload structure Each message contains a flat list of currency values: | Field | Type | Description | | --------------- | -------------- | ------------------------------------------------------- | | `currency` | `string` | Symbol of the currency/token (e.g. `BTC`, `USD`, `ADA`) | | `currencyValue` | `number` | Current exchange rate (float) | | `updatedAt` | `string (ISO)` | Time this value was last refreshed | *** ## Example message ```json theme={null} { "channel": "currencies", "type": "UPDATE", "payload": { "BTC": { "currency": "BTC", "currencyValue": 0.00001141, "updatedAt": "2025-12-28T18:38:02+00:00" } }, "ts": 1766939809876, "entryId": "1766939809876-700" } ``` *** ## Notes * All values are relative to the system's reference currency: USD # Fixtures Channel - Match Metadata & Schedules Source: https://docs.oddspapi.io/websocket/channels/fixtures Stream realtime fixture updates via WebSocket. Match status, start times, participants, tournaments, scores, and provider ID mappings for Betradar, Pinnacle, Flashscore. ## What it streams Metadata for a given `fixtureId` — including match status, start times, participants, and tournament/sport info. Also includes optional `scores` and mapped provider IDs. This is the **anchor stream** used to map odds/scores to a real-world fixture. *** ## Routing * Entity key: `payload.fixtureId` * Filters: `sportIds`, `tournamentIds`, `fixtureIds` * Access: live/pregame determined by your `apiKey` *** ## Payload fields | Field | Type | Description | | -------------------------------- | ---------------- | ------------------------------------------------------- | | `fixtureId` | `string` | Unique ID of the fixture | | `status` | `object` | Match status info | | `status.live` | `boolean` | True if currently live | | `status.statusId` | `number \| null` | Optional status code | | `status.statusName` | `string \| null` | Status name (e.g. "Live", "Postponed") | | `sport` | `object` | Sport metadata | | `sport.sportId` | `number` | Unique sport ID | | `sport.sportName` | `string` | Sport name | | `tournament` | `object` | Tournament metadata | | `tournament.tournamentId` | `number` | Unique tournament ID | | `tournament.tournamentName` | `string` | Tournament name | | `tournament.categoryName` | `string` | Geographic/organizational category | | `season` | `object` | Season metadata | | `season.seasonId` | `number \| null` | Season ID (nullable) | | `season.seasonName` | `string \| null` | Season name | | `startTime` | `number` | Scheduled start (epoch seconds UTC) | | `trueStartTime` | `string \| null` | Actual start time (ISO 8601) | | `trueEndTime` | `string \| null` | Actual end time (ISO 8601) | | `participants` | `object` | Competitor metadata | | `participants.participant1Id` | `number` | Team/player 1 ID | | `participants.participant1Name` | `string` | Team/player 1 name | | `participants.participant1Abbr` | `string \| null` | Optional abbreviation | | `participants.participant1RotNr` | `number \| null` | Optional rotation number | | `participants.participant2Id` | `number` | Team/player 2 ID | | `participants.participant2Name` | `string` | Team/player 2 name | | `participants.participant2Abbr` | `string \| null` | Optional abbreviation | | `participants.participant2RotNr` | `number \| null` | Optional rotation number | | `scores` | `object` | Optional score object (same format as `scores` stream) | | `expectedPeriods` | `number \| null` | Number of scheduled periods (e.g. halves/sets/quarters) | | `periodLength` | `number \| null` | Period duration in minutes | | `externalProviders` | `object` | Mapped provider IDs | | `externalProviders.betradarId` | `number \| null` | Betradar fixture ID | | `externalProviders.flashscoreId` | `string \| null` | Flashscore ID | | `externalProviders.pinnacleId` | `number \| null` | Pinnacle fixture ID | | `externalProviders.sofascoreId` | `number \| null` | Sofascore ID | | `externalProviders.oddinId` | `number \| null` | Oddin ID | | `externalProviders.mollybetId` | `string \| null` | Mollybet ID | | `externalProviders.opticoddsId` | `string \| null` | Opticodds ID | | `externalProviders.lsportsId` | `number \| null` | LSports ID | | `externalProviders.txoddsId` | `number \| null` | TXOdds ID | *** ## Example message (JSON) ```json theme={null} { "channel": "fixtures", "type": "UPDATE", "payload": { "fixtureId": "id1000046363014481", "status": { "live": true, "statusId": 1, "statusName": "Live" }, "sport": { "sportId": 10, "sportName": "Soccer" }, "tournament": { "tournamentId": 463, "tournamentName": "AFC Champions League Elite", "categoryName": "International Clubs" }, "season": { "seasonId": 131657, "seasonName": "AFC Champions League Elite 25/26" }, "startTime": 1766427300, "trueStartTime": "2025-12-22T18:15:38.441757+00:00", "trueEndTime": null, "participants": { "participant1Id": 61532, "participant1RotNr": null, "participant1Name": "Al Shorta SC", "participant1Abbr": null, "participant2Id": 34469, "participant2RotNr": null, "participant2Name": "Al Ahli Saudi FC", "participant2Abbr": null }, "scores": {}, "expectedPeriods": null, "periodLength": null, "externalProviders": { "betgeniusId": 12860147, "betradarId": 63014481, "flashscoreId": "hUsabPpR", "mollybetId": "2025-12-22,29690,26898", "oddinId": null, "opticoddsId": "20251222AF56C9CD", "pinnacleId": 1621307620, "sofascoreId": 14466133, "lsportsId": null, "txoddsId": null } }, "ts": 1766427338743, "entryId": "1766427338743-4273" } ``` ## Example: fixture update that includes a `scores.result` Some fixture updates include a `scores` object (for example, a pre-game or result snapshot). ```json theme={null} { "channel": "fixtures", "type": "UPDATE", "payload": { "fixtureId": "id1102138464027567", "status": { "live": false, "statusId": 0, "statusName": "Pre-Game" }, "sport": { "sportId": 11, "sportName": "Basketball" }, "tournament": { "tournamentId": 21384, "tournamentName": "NCAA Women, Regular Season", "categoryName": "USA" }, "season": { "seasonId": 133208, "seasonName": "NCAA Women, Regular Season 25/26" }, "startTime": 1766426400, "trueStartTime": "2025-12-22T18:03:13.535381+00:00", "trueEndTime": null, "participants": { "participant1Id": 347062, "participant1RotNr": null, "participant1Name": "Sam Houston State Bearkats", "participant1Abbr": null, "participant2Id": 346978, "participant2RotNr": null, "participant2Name": "Northern Colorado Bears", "participant2Abbr": null }, "scores": { "result": { "period": "result", "participant1Score": 7, "participant2Score": 2, "updatedAt": "2025-12-22T18:12:16.755551+00:00" } }, "expectedPeriods": null, "periodLength": null, "externalProviders": { "betgeniusId": null, "betradarId": 64027567, "flashscoreId": "lxgZJCUG", "mollybetId": null, "oddinId": null, "opticoddsId": null, "pinnacleId": null, "sofascoreId": null, "lsportsId": null, "txoddsId": null } }, "ts": 1766427343630, "entryId": "1766427343630-4278" } ``` # Futures Channel - Season & Outright Markets Source: https://docs.oddspapi.io/websocket/channels/futures Stream futures and outright betting markets via WebSocket. Season-long markets, tournament winners, championship odds with timing windows and provider mappings. ## What it streams Metadata about long-term or season-based betting markets (called “futures”), scoped to a `futureId`. Includes tournament/season mapping, market metadata, timing window, and external provider IDs. *** ## Routing * Entity key: `payload.futureId` * Filters: `sportIds`, `tournamentIds`, `futureIds` * Access: live vs pregame determined by your `apiKey` *** ## Payload fields | Field | Type | Description | | -------------------------------- | ----------------- | --------------------------------------------------- | | `futureId` | `string` | Unique identifier for the future | | `status` | `object` | Live/pregame status | | `status.live` | `boolean` | Whether the future is currently live | | `status.statusId` | `number \| null` | Optional status code | | `status.statusName` | `string \| null` | Optional status label (e.g. `"Pre-Game"`, `"Live"`) | | `sport` | `object` | Sport metadata | | `sport.sportId` | `number` | Unique sport ID | | `sport.sportName` | `string` | Human-readable sport name | | `tournament` | `object` | Tournament metadata | | `tournament.tournamentId` | `number` | Unique tournament ID | | `tournament.tournamentName` | `string` | Tournament name | | `tournament.categoryName` | `string` | Geographic/organizational grouping | | `season` | `object` | Season metadata | | `season.seasonId` | `number \| null` | Season ID (nullable) | | `season.seasonName` | `string \| null` | Season name | | `startTime` | `number` | Start of the betting window (epoch seconds UTC) | | `endTime` | `number` | End of the betting window (epoch seconds UTC) | | `market` | `object \| null` | Market metadata (nullable) | | `market.marketId` | `number \| null` | Optional market ID | | `market.marketName` | `string \| null` | Optional market name (e.g. `"Outright Winner"`) | | `market.marketType` | `string \| null` | Optional market type code | | `market.playerMarket` | `boolean \| null` | True if this is a player-specific market | | `market.participantMarket` | `boolean \| null` | True if this is a participant/team market | | `externalProviders` | `object` | Mapped external provider IDs | | `externalProviders.betradarId` | `number \| null` | Betradar ID | | `externalProviders.flashscoreId` | `string \| null` | Flashscore ID | | `externalProviders.opticoddsId` | `string \| null` | OpticOdds ID | | `externalProviders.polymarketId` | `string \| null` | Polymarket ID | | `externalProviders.kalshiId` | `string \| null` | Kalshi ID | | `externalProviders.sofascoreId` | `number \| null` | Sofascore ID | | `bookmakers` | `object` | Odds availability status (see `bookmakersFutures`) | *** ## Example: future metadata ```json theme={null} { "channel": "futures", "type": "UPDATE", "payload": { "futureId": "id11047437137982", "status": { "live": true, "statusId": 1, "statusName": "Live" }, "sport": { "sportId": 11, "sportName": "Basketball" }, "tournament": { "tournamentId": 47437, "tournamentName": "NBL", "categoryName": "China" }, "season": { "seasonId": 137982, "seasonName": "NBL 25/26" }, "startTime": 1766188800, "endTime": 1777334399, "market": { "marketId": null, "marketName": null, "marketType": null, "playerMarket": null, "participantMarket": null }, "externalProviders": { "betradarId": 137982, "flashscoreId": null, "opticoddsId": null, "polymarketId": null, "kalshiId": null, "sofascoreId": null }, "bookmakers": {} }, "ts": 1766939800000, "entryId": "1766939800000-999" } ``` *** ## Notes * Odds are streamed separately via the [`oddsFutures`](/websocket/channels/oddsFutures) channel * Use `futureId` to join with: * `oddsFutures` (for prices) * `bookmakersFutures` (for status per bookmaker) * Most `market` fields may be `null` for legacy or non-structured markets # Odds Channel - Realtime Betting Odds Stream Source: https://docs.oddspapi.io/websocket/channels/odds High-throughput realtime betting odds via WebSocket. Stream live odds from 100+ bookmakers including Pinnacle, Bet365, Polymarket. Decimal, fractional, American formats. ## What it streams Realtime odds updates for outcomes within markets, scoped to a specific `fixtureId`. Odds are grouped by bookmaker and keyed by a unique **oddsId** per outcome. Each entry represents a single **oddsId** (one price for one outcome). *** ## Routing * Entity key: `payload.fixtureId` * Filters: `sportIds`, `tournamentIds`, `fixtureIds`, `bookmakers` * Access: determined by your `apiKey` * Bookmaker-gated: ✅ Yes *** ## Delivery semantics * This channel is **high throughput** * Updates are **latest-state only** * The gateway may coalesce or drop intermediate updates under load * Do **not** assume tick-by-tick completeness Treat every message as a **state update**, not a ledger. *** ## Payload structure oddsId: ``` ::: ``` *** ## outcome object (full schema) Each odds entry is an **outcome**, with the following fields: | Field | Type | Description | | | -------------------- | ----------------- | ------------------------------------------------------------- | ----------------------------------- | | `bookmaker` | `string` | Bookmaker slug (e.g. `"stake"`, `"pinnacle"`, `"polymarket"`) | | | `outcomeId` | `integer` | Outcome identifier | | | `playerId` | `integer` | Player ID (`0` for non-player markets) | | | `price` | `number` | Decimal odds | | | `active` | `boolean` | Whether this outcome is currently available | | | `marketActive` | `boolean \| null` | Whether the entire market is active | | | `mainLine` | `boolean \| null` | Whether this is the bookmaker’s main line | | | `marketId` | `integer` | Market identifier | | | `bookmakerMarketId` | `string \| null` | Native bookmaker market ID | | | `bookmakerOutcomeId` | `string \| null` | Native bookmaker outcome ID | | | `bookmakerChangedAt` | `number \| null` | Bookmaker-provided change timestamp (epoch ms) | | | `priceFractional` | \`string | \` | Fractional odds (e.g. `"5/2"`) | | `priceAmerican` | \`integer | \` | American odds (e.g. `-110`, `+250`) | | `limit` | `number \| null` | Maximum accepted stake (if provided) | | | `betslip` | `string \| null` | Optional bookmaker betslip or deeplink token | | | `meta` | `object \| null` | Bookmaker-specific metadata (orderbooks, ladders, etc.) | | | `changedAt` | `number` | Gateway change timestamp (epoch ms, UTC) | | *** ## Notes on timestamps * `changedAt` is **always present** and represents when the gateway accepted the update * `bookmakerChangedAt` (when present) reflects the bookmaker’s own timestamp * These values may differ — do not assume equality *** ## Advanced metadata (`meta`) Some bookmakers (e.g. prediction markets / exchanges) provide rich metadata. Example: ```json theme={null} { "meta": { "lay": [ { "price": 2.00, "size": 100.0 }, { "price": 2.10, "size": 80.0 } ], "back": [ { "price": 1.95, "size": 50.0 } ] } } ``` Typical `meta` contents may include: * Orderbook ladders (`back` / `lay`) * Liquidity hints * Internal sizing or tick metadata The schema of `meta` is **bookmaker-specific** and may evolve. *** ## Example: traditional bookmaker odds ```json theme={null} { "channel": "odds", "type": "UPDATE", "payload": { "fixtureId": "id1100013262924543", "odds": { "stake": { "id1100013262924543:stake:111:0": { "bookmaker": "stake", "outcomeId": 111, "playerId": 0, "active": true, "price": 1.91, "marketActive": true, "mainLine": true, "changedAt": 1766427330098 } } } }, "ts": 1766427330257, "entryId": "1766427330257-84805" } ``` *** ## Example: prediction market odds (extended fields) ```json theme={null} { "channel": "odds", "type": "UPDATE", "payload": { "fixtureId": "id1100064864029581", "odds": { "polymarket": { "id1100064864029581:polymarket:112:0": { "bookmaker": "polymarket", "outcomeId": 112, "playerId": 0, "active": true, "price": 6.369, "priceAmerican": 537, "limit": 4.71, "bookmakerMarketId": "1011497", "bookmakerOutcomeId": "4937...", "meta": { "back": [{ "price": 6.369, "size": 30.0 }], "lay": [{ "price": 100.0, "size": 15.0 }] }, "marketActive": true, "changedAt": 1766939876376 } } } }, "ts": 1766939876700, "entryId": "1766939876700-653" } ``` *** ## Implementation guidance * Always key storage by ``` {fixtureId}:{bookmaker}:{outcomeId}:{playerId} ``` * Group outcomes by `marketId` (see **Concepts**) for: * arbitrage detection * overround calculations * probability normalization * Treat `active=false` or `marketActive=false` as **hard stops** * Preserve unknown fields in `meta` to remain forward-compatible *** # Scores Channel - Live Score Updates Source: https://docs.oddspapi.io/websocket/channels/scores Stream realtime live scores via WebSocket. Period-by-period score updates for all sports including result, halftime, quarters, sets, and periods. ## What it streams Realtime score updates scoped to a specific `fixtureId`. Each `payload.scores` object is keyed by the period (`result`, `p1`, etc.). *** ## Routing * Entity key: `payload.fixtureId` * Filters: `sportIds`, `tournamentIds`, `fixtureIds` * Access: live/pregame access is determined by your `apiKey` *** ## Payload structure | Field | Type | Description | | ---------------- | -------------- | -------------------------------------- | | `fixtureId` | `string` | The fixture this score applies to | | `scores` | `object` | Scores per period | | `scores[period]` | `object` | Each period's score and metadata | | `updatedAt` | `string (ISO)` | Last known update time for this period | *** ## Example: result update ```json theme={null} { "channel": "scores", "type": "UPDATE", "payload": { "fixtureId": "id1500025662664057", "scores": { "result": { "period": "result", "participant1Score": 2, "participant2Score": 1, "updatedAt": "2025-12-28T16:24:11.426852+00:00" } } }, "ts": 1766939805321, "entryId": "1766939805321-3077" } ``` ## Example: multiple period updates ```json theme={null} { "channel": "scores", "type": "UPDATE", "payload": { "fixtureId": "id2503637767171366", "scores": { "p1": { "period": "p1", "participant1Score": 7, "participant2Score": 6, "updatedAt": "2025-12-28T16:34:02.865934+00:00" }, "result": { "period": "result", "participant1Score": 0, "participant2Score": 0, "updatedAt": "2025-12-28T16:32:18.616082+00:00" } } }, "ts": 1766939642953, "entryId": "1766939642953-1905" } ``` *** ## Notes * Periods may include `result`, `p1`, `1stHalf`, etc. * Use `updatedAt` to detect stale scores * This stream **does not** include match status (see `fixtures`) # Interactive WebSocket Console - Test Live Data Source: https://docs.oddspapi.io/websocket/console Test OddsPapi WebSocket API in your browser. Interactive console for connecting to the gateway, subscribing to channels, and viewing realtime sports data.