{"openapi": "3.2.0", "info": {"description": "Connect your server to **pre-match and live eSoccer odds**: fixture metadata, price changes,\nbet stops, results, settlements, cancellations and rollbacks.\n\n**[Read the guide \u2192](guide/)** It explains how to start, gives a minimal app in Python and\nNode.js, and describes the odds stream, reconnects, HTTP/3, settlements, voids and every event.\n\nThis page is the API reference: every route, parameter, response and stream event model.\nSend your key in the `X-API-Key` header. Download the [OpenAPI YAML](openapi.yaml) or\n[OpenAPI JSON](openapi.json).\n", "title": "Tantu eSoccer", "version": "0.1.0", "x-docs-label": "eSoccer API"}, "servers": [{"url": "https://dev.feed.sportlive.hr"}], "tags": [{"name": "Catalog", "description": "Discover sports, tournaments, fixtures and market reference descriptions."}, {"name": "Odds", "description": "Read current pre-match and live eSoccer prices and stream typed changes."}, {"name": "Accounting", "description": "Recover settlements, cancellations and corrections durably."}], "paths": {"/tenant-catalog-api/categories": {"servers": [], "get": {"description": "Categories available to your subscription, with their sport identifiers and country codes.", "operationId": "catalogListCategories", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/CategoryResponse"}, "type": "array"}, "example": [{"urn": "sportlive:category:110610", "sportUrn": "sportlive:sport:2", "name": "Esoccer", "countryCode": "GB"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "List categories", "tags": ["Catalog"]}}, "/tenant-catalog-api/categories/{urn}": {"servers": [], "get": {"description": "Read a category by its identifier. Unknown and not-entitled identifiers both return 404.", "operationId": "catalogGetCategory", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "path", "name": "urn", "required": true, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CategoryResponse"}, "example": {"urn": "sportlive:category:110610", "sportUrn": "sportlive:sport:2", "name": "Esoccer", "countryCode": "GB"}}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"description": "The identifier is unknown or outside your subscription. These cases are indistinguishable."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get a category", "tags": ["Catalog"]}}, "/tenant-catalog-api/competitors/{urn}": {"servers": [], "get": {"description": "Read a competitor by its identifier. Unknown and not-entitled identifiers both return 404.", "operationId": "catalogGetCompetitor", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "path", "name": "urn", "required": true, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CompetitorResponse"}, "example": {"urn": "sportlive:competitor:42001", "sportUrn": "sportlive:sport:2", "name": "Real Madrid (Nathan)", "abbreviation": "RMA", "countryCode": "ES"}}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"description": "The identifier is unknown or outside your subscription. These cases are indistinguishable."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get a competitor", "tags": ["Catalog"]}}, "/tenant-catalog-api/descriptions/betstop_reasons": {"servers": [], "get": {"description": "Reason codes explaining why betting is paused. Available without an API key.", "operationId": "catalogListBetstopReasons", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ReasonDescription"}, "type": "array"}, "example": [{"id": 1, "description": "POSSIBLE_GOAL"}, {"id": 2, "description": "POSSIBLE_RED_CARD"}, {"id": 8, "description": "POSSIBLE_PENALTY"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List reasons for paused betting", "tags": ["Catalog"]}}, "/tenant-catalog-api/descriptions/betting_status": {"servers": [], "get": {"description": "Codes for open, suspended and closed markets. Available without an API key.", "operationId": "catalogListBettingStatuses", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ReasonDescription"}, "type": "array"}, "example": [{"id": 1, "description": "GOAL"}, {"id": 2, "description": "DANGEROUS_FREE_KICK"}, {"id": 7, "description": "POSSIBLE_GOAL"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List betting statuses", "tags": ["Catalog"]}}, "/tenant-catalog-api/descriptions/markets": {"servers": [], "get": {"description": "Full market dictionary with names, groups and outcomes. Available without an API key. Spread market ids 2100001-2199999 use a single buy quote in the market's unit, not decimal odds; they settle to a make-up value.", "operationId": "catalogListMarketDictionary", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/CustomerMarketDescription"}, "type": "array"}, "example": [{"id": 1, "name": "1x2", "groups": ["all", "score", "regular_play"], "outcomes": [{"id": "1", "name": "{$competitor1}"}, {"id": "2", "name": "draw"}, {"id": "3", "name": "{$competitor2}"}]}, {"id": 18, "name": "Total", "groups": ["all", "score", "regular_play"], "outcomes": [{"id": "12", "name": "over {total}"}, {"id": "13", "name": "under {total}"}]}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List the market dictionary", "tags": ["Catalog"]}}, "/tenant-catalog-api/descriptions/match_status": {"servers": [], "get": {"description": "Match state codes, descriptions and optional period numbers. Available without an API key.", "operationId": "catalogListMatchStatuses", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/CustomerMatchStatusDescription"}, "type": "array"}, "example": [{"id": 6, "description": "1st half", "periodNumber": 1}, {"id": 7, "description": "2nd half", "periodNumber": 2}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List match statuses", "tags": ["Catalog"]}}, "/tenant-catalog-api/descriptions/void_reasons": {"servers": [], "get": {"description": "Reason codes explaining why a settlement is void. Available without an API key.", "operationId": "catalogListVoidReasons", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ReasonDescription"}, "type": "array"}, "example": [{"id": 3, "description": "RESULT_UNVERIFIABLE"}, {"id": 4, "description": "FORMAT_CHANGE"}, {"id": 5, "description": "CANCELLED_EVENT"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List void reasons", "tags": ["Catalog"]}}, "/tenant-catalog-api/fixtures/resolved": {"servers": [], "get": {"description": "Repeatable `urn` (max 512). Answers with the entitled rows only. Unknown and not-entitled identifiers are both omitted; the answer is 200, including when empty. Names are null when unavailable, never an identifier used as a label.", "operationId": "catalogResolveFixtures", "parameters": [{"description": "Fixture urns, comma-separated or repeated.", "in": "query", "name": "urn", "required": false, "schema": {"items": {"type": "string"}, "type": "array"}}, {"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ResolvedFixtureResponse"}, "type": "array"}, "example": [{"urn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "tournamentUrn": "sportlive:tournament:110611", "name": "Real Madrid (Nathan) vs Inter (Kray)", "scheduledTime": "2026-10-14T12:00:00Z", "sportName": "Esoccer", "categoryName": "Esoccer", "tournamentName": "Esoccer Battle - 8 mins play", "countryCode": "GB", "competitors": [{"urn": "sportlive:competitor:42001", "name": "Real Madrid (Nathan)", "abbreviation": "RMA"}, {"urn": "sportlive:competitor:42002", "name": "Inter (Kray)", "abbreviation": "INT"}]}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "400": {"description": "More than 512 distinct fixture identifiers were requested."}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get fixtures with display names", "tags": ["Catalog"]}}, "/tenant-catalog-api/fixtures/{urn}": {"servers": [], "get": {"description": "Read a fixture by its identifier. Unknown and not-entitled identifiers both return 404.", "operationId": "catalogGetFixture", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "path", "name": "urn", "required": true, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/FixtureResponse"}, "example": {"urn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "tournamentUrn": "sportlive:tournament:110611", "name": "Real Madrid (Nathan) vs Inter (Kray)", "scheduledTime": "2026-10-14T12:00:00Z", "liveOdds": 1}}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"description": "The identifier is unknown or outside your subscription. These cases are indistinguishable."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get a fixture", "tags": ["Catalog"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-catalog-api/fixtures/sportlive:match:9001\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-catalog-api/fixtures/sportlive:match:9001',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-catalog-api/fixtures/sportlive:match:9001',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-catalog-api/markets": {"servers": [], "get": {"description": "Market names and outcomes available to your subscription. Spread market ids 2100001-2199999 have one buy outcome. Its quote is in goals, corners or booking points, not decimal odds, and can be zero or negative. Spreads are long-only, cover regular time, and settle to a make-up value. Profit is (make-up - buy quote) times stake per point. Do not apply implied-probability or overround calculations to spread quotes.", "operationId": "catalogListMarkets", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/MarketResponse"}, "type": "array"}, "example": [{"id": 1, "name": "1x2", "groups": "all|score|regular_play", "outcomes": [{"id": "1", "name": "{$competitor1}"}, {"id": "2", "name": "draw"}, {"id": "3", "name": "{$competitor2}"}], "outcomeType": "decimal"}, {"id": 18, "name": "Total", "groups": "all|score|regular_play", "outcomes": [{"id": "12", "name": "over {total}"}, {"id": "13", "name": "under {total}"}], "outcomeType": "decimal"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "List market descriptions", "tags": ["Catalog"]}}, "/tenant-catalog-api/producers": {"servers": [], "get": {"description": "One odds delivery producer with live and prematch scope and an active flag. Available without an API key.", "operationId": "catalogListFeedTypes", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ProducerDescription"}, "type": "array"}, "example": [{"id": 1, "name": "live", "description": "Odds delivery", "active": true, "scope": "live|prematch"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}}, "security": [], "summary": "List delivery producers", "tags": ["Catalog"]}}, "/tenant-catalog-api/sports": {"servers": [], "get": {"description": "Sports available to your subscription. Revalidate cached answers with If-None-Match.", "operationId": "catalogListSports", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/SportResponse"}, "type": "array"}, "example": [{"urn": "sportlive:sport:2", "name": "Esoccer"}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "List sports", "tags": ["Catalog"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-catalog-api/sports\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-catalog-api/sports',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-catalog-api/sports',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-catalog-api/sports/{urn}": {"servers": [], "get": {"description": "Read a sport by its identifier. Unknown and not-entitled identifiers both return 404.", "operationId": "catalogGetSport", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "path", "name": "urn", "required": true, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SportResponse"}, "example": {"urn": "sportlive:sport:2", "name": "Esoccer"}}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"description": "The identifier is unknown or outside your subscription. These cases are indistinguishable."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get a sport", "tags": ["Catalog"]}}, "/tenant-catalog-api/tournaments": {"servers": [], "get": {"description": "Tournaments available to your subscription, including their fixture schedules.", "operationId": "catalogListTournaments", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TournamentResponse"}, "type": "array"}, "example": [{"urn": "sportlive:tournament:110611", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "name": "Esoccer Battle - 8 mins play", "fixtures": [{"urn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "tournamentUrn": "sportlive:tournament:110611", "name": "Real Madrid (Nathan) vs Inter (Kray)", "scheduledTime": "2026-10-14T12:00:00Z", "liveOdds": 1}]}]}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "List tournaments", "tags": ["Catalog"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-catalog-api/tournaments\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-catalog-api/tournaments',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-catalog-api/tournaments',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-catalog-api/tournaments/{urn}": {"servers": [], "get": {"description": "Read a tournament and its fixture schedule. Unknown and not-entitled identifiers both return 404.", "operationId": "catalogGetTournament", "parameters": [{"description": "Send the ETag from the previous answer. An exact match returns 304 with no body.", "in": "header", "name": "If-None-Match", "required": false, "schema": {"type": "string"}}, {"in": "path", "name": "urn", "required": true, "schema": {"type": "string"}}, {"in": "query", "name": "locale", "required": false, "schema": {"default": "en", "type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TournamentResponse"}, "example": {"urn": "sportlive:tournament:110611", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "name": "Esoccer Battle - 8 mins play", "fixtures": [{"urn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "categoryUrn": "sportlive:category:110610", "tournamentUrn": "sportlive:tournament:110611", "name": "Real Madrid (Nathan) vs Inter (Kray)", "scheduledTime": "2026-10-14T12:00:00Z", "liveOdds": 1}]}}}, "description": "OK", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "304": {"description": "The cached answer is unchanged. No response body.", "headers": {"Cache-Control": {"description": "`private, max-age=0, must-revalidate`: store the answer only in your own client and revalidate it with If-None-Match on every use.", "schema": {"type": "string"}}, "ETag": {"description": "Quoted content hash. Save it for the next If-None-Match request.", "schema": {"type": "string"}}, "Vary": {"description": "`X-API-Key`: the answer belongs to the key that asked. A shared cache must not reuse it for another key.", "schema": {"type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"description": "The identifier is unknown or outside your subscription. These cases are indistinguishable."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get a tournament", "tags": ["Catalog"]}}, "/tenant-odds-output/odds/accounting": {"servers": [], "get": {"description": "Use after or since exclusively. Journal order is authoritative. Accounting changes your bets, not your odds board.", "operationId": "page", "parameters": [{"in": "query", "name": "after", "required": false, "schema": {"pattern": "^[0-9]+\\.[0-9]+$", "type": "string"}}, {"in": "query", "name": "limit", "required": false, "schema": {"default": 500, "format": "int32", "maximum": 1000, "minimum": 1, "type": "integer"}}, {"in": "query", "name": "since", "required": false, "schema": {"format": "int64", "minimum": 0, "type": "integer"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountingPage"}, "example": {"coveredFrom": 1791975920000, "events": [{"event": "bet_settlement", "data": {"accountingId": "8b724a5369f04156b28d30eaaf2918c7", "fixtureUrn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "certainty": 1, "producedAt": 1791979680000, "sentAt": 1791979680100, "markets": [{"marketId": 1, "specifiers": {}, "line": "", "outcomes": [{"outcomeId": "1", "result": "won"}, {"outcomeId": "2", "result": "lost"}, {"outcomeId": "3", "result": "lost"}]}]}}], "more": false, "next": "14792.1791979680100"}}}, "description": "Tenant accounting in journal order; available during odds warm-up.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "400": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountingError"}, "example": {"error": "invalid_since"}}}, "description": "Invalid cursor, parameters, limit or fixture ids.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountingUnavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "Busy (retry 1 s) or unavailable (retry 5 s); keep the cursor unchanged.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}, "Retry-After": {"schema": {"example": 5, "format": "int32", "type": "integer"}}}}}, "security": [{"ApiKey": []}], "summary": "Read the tenant accounting log", "tags": ["Accounting"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/accounting?since=0&limit=500\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-odds-output/odds/accounting?since=0&limit=500',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-odds-output/odds/accounting?since=0&limit=500',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-odds-output/odds/accounting/fixtures": {"servers": [], "get": {"description": "Repeat fixture (1 to 50 match ids); since is the oldest accounting window needed. complete=false means leave those bets unresolved. Missing fixtures are unknown or outside current scope.", "operationId": "fixtures_1", "parameters": [{"explode": true, "in": "query", "name": "fixture", "required": true, "schema": {"items": {"pattern": "^sportlive:match:[0-9]+$", "type": "string"}, "maxItems": 50, "minItems": 1, "type": "array"}, "style": "form"}, {"in": "query", "name": "since", "required": true, "schema": {"format": "int64", "minimum": 0, "type": "integer"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/FixtureAccountingResponse"}, "example": {"fixtures": [{"fixtureUrn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "asOf": 1791979680100, "complete": true, "lines": [{"marketId": 1, "specifiers": {}, "line": "", "state": "settled", "outcomes": [{"outcomeId": "1", "result": "won"}, {"outcomeId": "2", "result": "lost"}, {"outcomeId": "3", "result": "lost"}]}]}]}}}, "description": "Tenant accounting in journal order; available during odds warm-up.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "400": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountingError"}, "example": {"error": "invalid_since"}}}, "description": "Invalid cursor, parameters, limit or fixture ids.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountingUnavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "Busy (retry 1 s) or unavailable (retry 5 s); keep the cursor unchanged.", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}, "Retry-After": {"schema": {"example": 5, "format": "int32", "type": "integer"}}}}}, "security": [{"ApiKey": []}], "summary": "Reconcile fixture accounting after a gap", "tags": ["Accounting"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/accounting/fixtures?fixture=sportlive:match:1&since=0\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-odds-output/odds/accounting/fixtures?fixture=sportlive:match:1&since=0',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-odds-output/odds/accounting/fixtures?fixture=sportlive:match:1&since=0',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-odds-output/odds/events": {"servers": [], "get": {"description": "Keep X-API-Key on your server. Repeat sport and fixture filters to select ids. Fetch /odds/fixtures then send its cut as Last-Event-ID with the same filters for gap-free delivery. A snapshot_start clears client state and the resume id. During warm-up only alive is sent; after 60 seconds a partial snapshot and live events are served. A warmed snapshot follows clean recovery.", "operationId": "events", "parameters": [{"explode": true, "in": "query", "name": "fixture", "required": false, "schema": {"items": {"pattern": "^sportlive:match:[0-9]+$", "type": "string"}, "type": "array"}, "style": "form"}, {"explode": true, "in": "query", "name": "sport", "required": false, "schema": {"items": {"pattern": "^sportlive:sport:[0-9]+$", "type": "string"}, "type": "array"}, "style": "form"}, {"in": "header", "name": "Last-Event-ID", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"content": {"text/event-stream": {"examples": {"alive": {"summary": "alive", "value": {"data": "{\n  \"feeds\": [\n    {\n      \"feed\": \"live\",\n      \"status\": \"up\"\n    },\n    {\n      \"feed\": \"prematch\",\n      \"status\": \"up\"\n    }\n  ],\n  \"sentAt\": 1800000000000\n}", "event": "alive"}}, "bet_cancel": {"summary": "bet_cancel", "value": {"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde1\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"from\": 1799999995000,\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomeIds\": [\n        \"1\"\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\",\n  \"to\": 1800000000000\n}", "event": "bet_cancel", "id": "demo.42"}}, "bet_settlement": {"summary": "bet_settlement", "value": {"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcdef\",\n  \"certainty\": 1,\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomes\": [\n        {\n          \"deadHeatFactor\": 0.5,\n          \"outcomeId\": \"1\",\n          \"result\": \"won\",\n          \"voidFactor\": 0.5\n        }\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "bet_settlement", "id": "demo.42"}}, "bet_stop": {"summary": "bet_stop", "value": {"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"reason\": 900,\n  \"scope\": \"markets\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\",\n  \"status\": \"suspended\"\n}", "event": "bet_stop", "id": "demo.42"}}, "fixture_change": {"summary": "fixture_change", "value": {"data": "{\n  \"changeType\": \"status\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"lastModified\": 1800000000000,\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_change", "id": "demo.42"}}, "fixture_removed": {"summary": "fixture_removed", "value": {"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"producedAt\": 1800000000000,\n  \"reason\": \"ended\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_removed", "id": "demo.42"}}, "fixture_snapshot": {"summary": "fixture_snapshot", "value": {"data": "{\n  \"fixture\": {\n    \"fixtureUrn\": \"sportlive:match:9001\",\n    \"markets\": [\n      {\n        \"extendedSpecifiers\": {\n          \"score\": \"0:0\"\n        },\n        \"line\": \"hcp=-0.5|total=2.5\",\n        \"marketId\": 1,\n        \"outcomes\": [\n          {\n            \"active\": true,\n            \"odds\": 1.85,\n            \"outcomeId\": \"1\"\n          }\n        ],\n        \"specifiers\": {\n          \"hcp\": \"-0.5\",\n          \"total\": \"2.5\"\n        },\n        \"status\": \"active\"\n      }\n    ],\n    \"matchStatus\": {\n      \"awayScore\": 0,\n      \"homeScore\": 0,\n      \"status\": \"live\"\n    },\n    \"sportUrn\": \"sportlive:sport:2\",\n    \"updatedAt\": 1800000000000\n  },\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"reason\": \"snapshot\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_snapshot"}}, "odds_change": {"summary": "odds_change", "value": {"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomes\": [\n        {\n          \"active\": true,\n          \"odds\": 1.85,\n          \"outcomeId\": \"1\"\n        }\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      },\n      \"status\": \"active\"\n    }\n  ],\n  \"matchStatus\": {\n    \"awayScore\": 0,\n    \"homeScore\": 0,\n    \"status\": \"live\"\n  },\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "odds_change", "id": "demo.42"}}, "rollback_bet_cancel": {"summary": "rollback_bet_cancel", "value": {"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde3\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "rollback_bet_cancel", "id": "demo.42"}}, "rollback_bet_settlement": {"summary": "rollback_bet_settlement", "value": {"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde2\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "rollback_bet_settlement", "id": "demo.42"}}, "snapshot_complete": {"summary": "snapshot_complete", "value": {"data": "{\n  \"fixtures\": 1,\n  \"sentAt\": 1800000000000\n}", "event": "snapshot_complete", "id": "demo.42"}}, "snapshot_start": {"summary": "snapshot_start", "value": {"data": "{\n  \"reason\": \"connect\",\n  \"sentAt\": 1800000000000\n}", "event": "snapshot_start", "id": ""}}}, "itemSchema": {"description": "One framed SSE event. The connection delivers a sequence of these items.", "oneOf": [{"$ref": "#/components/schemas/Stream_alive"}, {"$ref": "#/components/schemas/Stream_bet_cancel"}, {"$ref": "#/components/schemas/Stream_bet_settlement"}, {"$ref": "#/components/schemas/Stream_bet_stop"}, {"$ref": "#/components/schemas/Stream_fixture_change"}, {"$ref": "#/components/schemas/Stream_fixture_removed"}, {"$ref": "#/components/schemas/Stream_fixture_snapshot"}, {"$ref": "#/components/schemas/Stream_odds_change"}, {"$ref": "#/components/schemas/Stream_rollback_bet_cancel"}, {"$ref": "#/components/schemas/Stream_rollback_bet_settlement"}, {"$ref": "#/components/schemas/Stream_snapshot_complete"}, {"$ref": "#/components/schemas/Stream_snapshot_start"}], "discriminator": {"propertyName": "event", "mapping": {"alive": "#/components/schemas/Stream_alive", "bet_cancel": "#/components/schemas/Stream_bet_cancel", "bet_settlement": "#/components/schemas/Stream_bet_settlement", "bet_stop": "#/components/schemas/Stream_bet_stop", "fixture_change": "#/components/schemas/Stream_fixture_change", "fixture_removed": "#/components/schemas/Stream_fixture_removed", "fixture_snapshot": "#/components/schemas/Stream_fixture_snapshot", "odds_change": "#/components/schemas/Stream_odds_change", "rollback_bet_cancel": "#/components/schemas/Stream_rollback_bet_cancel", "rollback_bet_settlement": "#/components/schemas/Stream_rollback_bet_settlement", "snapshot_complete": "#/components/schemas/Stream_snapshot_complete", "snapshot_start": "#/components/schemas/Stream_snapshot_start"}}}}}, "description": "OK"}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "concurrent_streams", "retryAfterSeconds": 5}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Current odds as typed JSON events", "tags": ["Odds"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/events\" \\\n  -H \"X-API-Key: $API_KEY\" \\\n  -H \"Last-Event-ID: $CUT\" \\\n  --max-time 30 --output /dev/null"}, {"label": "Python", "lang": "Python", "source": "import json, os, time\nimport httpx\nfrom httpx_sse import connect_sse\nfrom your_app import replace_book, apply_event\nbase, key = os.environ['BASE'], os.environ['API_KEY']\nheaders = {'X-API-Key': key}\nnames = (\n    'snapshot_start', 'fixture_snapshot', 'snapshot_complete', 'odds_change',\n    'bet_stop', 'fixture_change', 'fixture_removed', 'alive', 'bet_settlement',\n    'bet_cancel', 'rollback_bet_settlement', 'rollback_bet_cancel',\n)\nhandlers = {name: lambda data, name=name: apply_event(name, data) for name in names}\nwith httpx.Client(timeout=30) as client:\n    response = client.get(base + '/tenant-odds-output/odds/fixtures', headers=headers)\n    response.raise_for_status()\n    snapshot = response.json()\n    replace_book(snapshot['fixtures'])\n    cursor = snapshot['cut']\n    while True:\n        try:\n            with connect_sse(\n                client, 'GET', base + '/tenant-odds-output/odds/events',\n                headers={**headers, 'Last-Event-ID': cursor},\n            ) as source:\n                source.response.raise_for_status()\n                for message in source.iter_sse():\n                    handlers[message.event](json.loads(message.data))\n                    if message.event == 'snapshot_start' or message.id:\n                        cursor = message.id\n        except httpx.HTTPStatusError:\n            raise  # Handle access and Retry-After before retrying.\n        except httpx.TransportError:\n            pass\n        time.sleep(2)"}, {"label": "JavaScript", "lang": "JavaScript", "source": "import { EventSource } from 'eventsource';\nimport { replaceBook, applyEvent } from './your-app.js';\nconst { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(BASE + '/tenant-odds-output/odds/fixtures', { headers });\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst snapshot = await response.json();\nreplaceBook(snapshot.fixtures);\nlet lastAppliedId = snapshot.cut;\nconst source = new EventSource(BASE + '/tenant-odds-output/odds/events', {\n  fetch: (url, init) => fetch(url, {\n    ...init,\n    headers: { ...init.headers, ...headers, 'Last-Event-ID': lastAppliedId },\n  }),\n});\nconst names = [\n  'snapshot_start', 'fixture_snapshot', 'snapshot_complete', 'odds_change',\n  'bet_stop', 'fixture_change', 'fixture_removed', 'alive', 'bet_settlement',\n  'bet_cancel', 'rollback_bet_settlement', 'rollback_bet_cancel',\n];\nfor (const name of names) {\n  source.addEventListener(name, message => {\n    try {\n      applyEvent(name, JSON.parse(message.data));\n      if (name === 'snapshot_start' || message.lastEventId) {\n        lastAppliedId = message.lastEventId;\n      }\n    } catch (error) {\n      source.close();  // Stop before an unapplied event can be skipped.\n      throw error;\n    }\n  });\n}\nsource.addEventListener('error', error => {\n  if (error.code === 401 || error.code === 402 || error.code === 403) {\n    source.close();  // Restore access before creating a new connection.\n  }\n  // Network failures reconnect automatically through the custom fetch above.\n});"}]}}, "/tenant-odds-output/odds/fixtures": {"servers": [], "get": {"description": "Read current fixture odds with optional sport and fixture filters. Use the returned cut as Last-Event-ID with the same filters to resume the live stream. While warming, retry after two seconds.", "operationId": "fixtures", "parameters": [{"explode": true, "in": "query", "name": "fixture", "required": false, "schema": {"items": {"pattern": "^sportlive:match:[0-9]+$", "type": "string"}, "type": "array"}, "style": "form"}, {"explode": true, "in": "query", "name": "sport", "required": false, "schema": {"items": {"pattern": "^sportlive:sport:[0-9]+$", "type": "string"}, "type": "array"}, "style": "form"}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/OddsSnapshot"}, "example": {"cut": "esoccer20261014.14792", "complete": true, "fixtures": [{"fixtureUrn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "updatedAt": 1791979520000, "lastEventId": "esoccer20261014.14792", "matchStatus": {"status": "live", "statusCode": 7, "homeScore": 2, "awayScore": 1, "clock": {"minute": 5, "seconds": 20}, "periodScores": [{"number": 1, "statusCode": 6, "homeScore": 1, "awayScore": 1}, {"number": 2, "statusCode": 7, "homeScore": 1, "awayScore": 0}]}, "markets": [{"marketId": 1, "specifiers": {}, "line": "", "status": "active", "outcomes": [{"outcomeId": "1", "odds": 1.72, "active": true}, {"outcomeId": "2", "odds": 4.1, "active": true}, {"outcomeId": "3", "odds": 3.8, "active": true}]}, {"marketId": 18, "specifiers": {"total": "4.5"}, "line": "total=4.5", "status": "active", "outcomes": [{"outcomeId": "12", "odds": 1.9, "active": true}, {"outcomeId": "13", "odds": 1.85, "active": true}]}]}]}}}, "description": "Current tenant odds", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WarmingError"}, "example": {"error": "warming", "retryAfterSeconds": 2}}}, "description": "The book is warming. Retry in two seconds.", "headers": {"Retry-After": {"schema": {"example": 2, "format": "int32", "type": "integer"}}}}}, "security": [{"ApiKey": []}], "summary": "List current fixture odds", "tags": ["Odds"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/fixtures\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-odds-output/odds/fixtures',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-odds-output/odds/fixtures',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-odds-output/odds/fixtures/{fixtureUrn}": {"servers": [], "get": {"description": "Read current odds for one fixture. Unknown fixtures and fixtures outside your subscription return the same 404 response. While warming, retry after two seconds.", "operationId": "fixture", "parameters": [{"in": "path", "name": "fixtureUrn", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/FixtureOdds"}, "example": {"fixtureUrn": "sportlive:match:9001", "sportUrn": "sportlive:sport:2", "updatedAt": 1791979520000, "lastEventId": "esoccer20261014.14792", "matchStatus": {"status": "live", "statusCode": 7, "homeScore": 2, "awayScore": 1, "clock": {"minute": 5, "seconds": 20}, "periodScores": [{"number": 1, "statusCode": 6, "homeScore": 1, "awayScore": 1}, {"number": 2, "statusCode": 7, "homeScore": 1, "awayScore": 0}]}, "markets": [{"marketId": 1, "specifiers": {}, "line": "", "status": "active", "outcomes": [{"outcomeId": "1", "odds": 1.72, "active": true}, {"outcomeId": "2", "odds": 4.1, "active": true}, {"outcomeId": "3", "odds": 3.8, "active": true}]}, {"marketId": 18, "specifiers": {"total": "4.5"}, "line": "total=4.5", "status": "active", "outcomes": [{"outcomeId": "12", "odds": 1.9, "active": true}, {"outcomeId": "13", "odds": 1.85, "active": true}]}]}}}, "description": "Current tenant odds", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "not_found"}}}, "description": "Fixture unknown or outside the tenant's scope."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WarmingError"}, "example": {"error": "warming", "retryAfterSeconds": 2}}}, "description": "The book is warming. Retry in two seconds.", "headers": {"Retry-After": {"schema": {"example": 2, "format": "int32", "type": "integer"}}}}}, "security": [{"ApiKey": []}], "summary": "Get current fixture odds", "tags": ["Odds"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/fixtures/sportlive:match:9001\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-odds-output/odds/fixtures/sportlive:match:9001',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-odds-output/odds/fixtures/sportlive:match:9001',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}, "/tenant-odds-output/odds/status": {"servers": [], "get": {"description": "Read routed-output transport health, the last odds update, live fixture count and warm-up state. Both live and prematch labels share one delivery stream and report the same heartbeat status. Up does not certify phase coverage, active prices or upstream freshness; warm reports snapshot recovery separately.", "operationId": "status", "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/OddsStatus"}, "example": {"lastOddsAt": 1791979520000, "liveFixtures": 12, "feeds": [{"feed": "live", "status": "up"}, {"feed": "prematch", "status": "up"}], "warm": "complete"}}}, "description": "Current tenant odds", "headers": {"Cache-Control": {"schema": {"default": "no-store", "type": "string"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"error": "missing or invalid X-API-Key"}}}, "description": "The API key is missing or unknown."}, "402": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentRequired"}, "example": {"error": "payment_required", "payUrl": "https://billing.example.com/pay/invoice-20261014"}}}, "description": "Access is paused for payment. Use payUrl to pay."}, "403": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Forbidden"}, "example": {"error": "not_entitled"}}}, "description": "suspended means access is paused. not_entitled means the key's tenant has no access to this API."}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RateLimited"}, "example": {"error": "rate_limited", "limit": "requests_per_minute", "retryAfterSeconds": 30}}}, "description": "A usage limit was reached. Wait for Retry-After seconds before retrying.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Unavailable"}, "example": {"error": "unavailable", "retryAfterSeconds": 5}}}, "description": "The API is briefly unavailable. Retry after Retry-After seconds.", "headers": {"Retry-After": {"$ref": "#/components/headers/Retry-After"}}}}, "security": [{"ApiKey": []}], "summary": "Get odds feed health", "tags": ["Odds"], "x-codeSamples": [{"label": "curl", "lang": "Shell", "source": "curl \"$BASE/tenant-odds-output/odds/status\" \\\n  -H \"X-API-Key: $API_KEY\""}, {"label": "Python", "lang": "Python", "source": "import os\nimport httpx\nbase = os.environ['BASE']\nheaders = {'X-API-Key': os.environ['API_KEY']}\nresponse = httpx.get(\n    base + '/tenant-odds-output/odds/status',\n    headers=headers,\n)\nresponse.raise_for_status()\nprint(response.json())"}, {"label": "JavaScript", "lang": "JavaScript", "source": "const { BASE, API_KEY } = process.env;\nconst headers = { 'X-API-Key': API_KEY };\nconst response = await fetch(\n  BASE + '/tenant-odds-output/odds/status',\n  { headers },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconsole.log(await response.json());"}]}}}, "components": {"headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"format": "int32", "minimum": 1, "type": "integer"}}}, "schemas": {"CategoryResponse": {"description": "A category with its sport identifier, display name and optional country code.", "properties": {"countryCode": {"type": ["null", "string"]}, "name": {"type": ["null", "string"]}, "sportUrn": {"type": "string"}, "urn": {"type": "string"}}, "type": "object"}, "CompetitorResponse": {"description": "A competitor with its identifier, sport, display name, abbreviation and optional country code.", "properties": {"abbreviation": {"type": ["null", "string"]}, "countryCode": {"type": ["null", "string"]}, "name": {"type": ["null", "string"]}, "sportUrn": {"type": "string"}, "urn": {"type": "string"}}, "type": "object"}, "CustomerMarketDescription": {"properties": {"groups": {"items": {"type": "string"}, "type": "array"}, "id": {"format": "int32", "type": "integer"}, "name": {"type": ["null", "string"]}, "outcomes": {"items": {"$ref": "#/components/schemas/OutcomeResponse"}, "type": "array"}}, "type": "object"}, "CustomerMatchStatusDescription": {"properties": {"description": {"type": "string"}, "id": {"format": "int32", "type": "integer"}, "periodNumber": {"format": "int32", "type": ["integer", "null"]}}, "type": "object"}, "Error": {"properties": {"error": {"type": "string"}}, "required": ["error"], "type": "object"}, "FixtureResponse": {"description": "A fixture with its hierarchy identifiers and scheduled start as an ISO-8601 instant. A null start means kickoff is to be determined.", "properties": {"categoryUrn": {"type": "string"}, "liveOdds": {"format": "int32", "type": "integer"}, "name": {"type": ["null", "string"]}, "scheduledTime": {"type": ["null", "string"]}, "sportUrn": {"type": "string"}, "tournamentUrn": {"type": "string"}, "urn": {"type": "string"}}, "type": "object"}, "Forbidden": {"properties": {"error": {"enum": ["not_entitled", "suspended"], "type": "string"}}, "required": ["error"], "type": "object"}, "MarketResponse": {"description": "A market identifier, display name and outcomes. Spread ids 2100001-2199999 use a single buy quote in goals, corners or booking points, not decimal odds, and settle to a make-up value.", "properties": {"groups": {"type": ["null", "string"]}, "id": {"format": "int32", "type": "integer"}, "name": {"type": ["null", "string"]}, "outcomeType": {"type": ["null", "string"]}, "outcomes": {"items": {"$ref": "#/components/schemas/OutcomeResponse"}, "type": "array"}}, "type": "object"}, "OutcomeResponse": {"description": "An outcome identifier and display name. A spread market has exactly one outcome, buy.", "properties": {"id": {"type": "string"}, "name": {"type": ["null", "string"]}}, "type": "object"}, "PaymentRequired": {"properties": {"error": {"enum": ["payment_required"], "type": "string"}, "payUrl": {"format": "uri", "type": "string"}}, "required": ["error"], "type": "object"}, "ProducerDescription": {"properties": {"active": {"type": "boolean"}, "description": {"type": "string"}, "id": {"format": "int32", "type": "integer"}, "name": {"type": "string"}, "scope": {"type": ["null", "string"]}}, "type": "object"}, "RateLimited": {"properties": {"error": {"type": "string"}, "limit": {"enum": ["concurrent_streams", "requests_per_minute"], "type": "string"}, "retryAfterSeconds": {"format": "int32", "minimum": 1, "type": "integer"}}, "required": ["error", "limit", "retryAfterSeconds"], "type": "object"}, "ReasonDescription": {"properties": {"description": {"type": "string"}, "id": {"format": "int32", "type": "integer"}}, "type": "object"}, "ResolvedCompetitorResponse": {"description": "A competitor identifier and optional display name and abbreviation. The first competitor is the home side.", "properties": {"abbreviation": {"type": ["null", "string"]}, "name": {"type": ["null", "string"]}, "urn": {"type": "string"}}, "type": "object"}, "ResolvedFixtureResponse": {"description": "A fixture with its sport, category, tournament and competitor names included. Unavailable names are null, never identifiers used as labels.", "properties": {"categoryName": {"type": ["null", "string"]}, "categoryUrn": {"type": "string"}, "competitors": {"items": {"$ref": "#/components/schemas/ResolvedCompetitorResponse"}, "type": "array"}, "countryCode": {"type": ["null", "string"]}, "name": {"type": ["null", "string"]}, "scheduledTime": {"type": ["null", "string"]}, "sportName": {"type": ["null", "string"]}, "sportUrn": {"type": "string"}, "tournamentName": {"type": ["null", "string"]}, "tournamentUrn": {"type": "string"}, "urn": {"type": "string"}}, "type": "object"}, "SportResponse": {"description": "A sport with its identifier and display name. An unavailable name is null.", "properties": {"name": {"type": ["null", "string"]}, "urn": {"type": "string"}}, "type": "object"}, "TournamentResponse": {"description": "A tournament with its category and sport identifiers and the fixtures available to your subscription.", "properties": {"categoryUrn": {"type": "string"}, "fixtures": {"items": {"$ref": "#/components/schemas/FixtureResponse"}, "type": "array"}, "name": {"type": ["null", "string"]}, "sportUrn": {"type": "string"}, "urn": {"type": "string"}}, "type": "object"}, "Unavailable": {"properties": {"error": {"enum": ["unavailable"], "type": "string"}, "retryAfterSeconds": {"format": "int32", "minimum": 1, "type": "integer"}}, "required": ["error", "retryAfterSeconds"], "type": "object"}, "AccountingError": {"properties": {"error": {"type": "string"}}, "required": ["error"], "type": "object"}, "AccountingEvent": {"discriminator": {"mapping": {"bet_cancel": "#/components/schemas/BetCancelAccountingEvent", "bet_settlement": "#/components/schemas/BetSettlementAccountingEvent", "rollback_bet_cancel": "#/components/schemas/RollbackBetCancelAccountingEvent", "rollback_bet_settlement": "#/components/schemas/RollbackBetSettlementAccountingEvent"}, "propertyName": "event"}, "oneOf": [{"$ref": "#/components/schemas/BetCancelAccountingEvent"}, {"$ref": "#/components/schemas/BetSettlementAccountingEvent"}, {"$ref": "#/components/schemas/RollbackBetCancelAccountingEvent"}, {"$ref": "#/components/schemas/RollbackBetSettlementAccountingEvent"}]}, "AccountingGap": {"properties": {"from": {"format": "int64", "type": "integer"}, "to": {"format": "int64", "type": "integer"}}, "required": ["from", "to"], "type": "object"}, "AccountingLine": {"properties": {"cancelFrom": {"format": "int64", "type": ["integer", "null"]}, "cancelTo": {"format": "int64", "type": ["integer", "null"]}, "extendedSpecifiers": {"additionalProperties": {"type": "string"}, "type": ["null", "object"]}, "line": {"type": "string"}, "marketId": {"format": "int32", "type": "integer"}, "operation": {"oneOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}]}, "outcomes": {"items": {"$ref": "#/components/schemas/AccountingOutcome"}, "type": "array"}, "specifiers": {"additionalProperties": {"type": "string"}, "type": "object"}, "state": {"enum": ["cancelled", "open", "settled"], "type": "string"}, "voidReason": {"format": "int32", "type": ["integer", "null"]}}, "required": ["line", "marketId", "outcomes", "specifiers", "state"], "type": "object"}, "AccountingOutcome": {"properties": {"deadHeatFactor": {"type": ["null", "number"]}, "outcomeId": {"type": "string"}, "result": {"enum": ["half_lost", "half_won", "lose_quarter", "lost", "void", "win_quarter", "won"], "type": ["null", "string"]}, "voidFactor": {"type": ["null", "number"]}}, "required": ["outcomeId"], "type": "object"}, "AccountingPage": {"properties": {"coveredFrom": {"format": "int64", "type": ["integer", "null"]}, "events": {"items": {"$ref": "#/components/schemas/AccountingEvent"}, "type": "array"}, "gap": {"oneOf": [{"$ref": "#/components/schemas/AccountingGap"}, {"type": "null"}]}, "more": {"type": "boolean"}, "next": {"type": "string"}}, "required": ["events", "more", "next"], "type": "object"}, "AccountingUnavailable": {"properties": {"error": {"type": "string"}, "retryAfterSeconds": {"format": "int32", "type": "integer"}}, "required": ["error", "retryAfterSeconds"], "type": "object"}, "AliveData": {"properties": {"feeds": {"items": {"$ref": "#/components/schemas/FeedHealth"}, "type": "array"}, "sentAt": {"format": "int64", "type": "integer"}}, "required": ["feeds", "sentAt"], "type": "object"}, "AliveEvent": {"properties": {"data": {"$ref": "#/components/schemas/AliveData"}, "event": {"const": "alive", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "BetCancelAccountingEvent": {"properties": {"data": {"$ref": "#/components/schemas/BetCancelData"}, "event": {"const": "bet_cancel", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "BetCancelData": {"properties": {"accountingId": {"description": "Stable accounting identity shared by the live stream and durable log.", "pattern": "^[0-9a-f]{32}$", "type": "string"}, "fixtureUrn": {"type": "string"}, "from": {"format": "int64", "type": ["integer", "null"]}, "markets": {"items": {"$ref": "#/components/schemas/CancelledMarket"}, "type": "array"}, "operation": {"oneOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}]}, "producedAt": {"format": "int64", "type": "integer"}, "sentAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}, "to": {"format": "int64", "type": ["integer", "null"]}}, "required": ["accountingId", "fixtureUrn", "markets", "producedAt", "sentAt"], "type": "object"}, "BetCancelEvent": {"properties": {"data": {"$ref": "#/components/schemas/BetCancelData"}, "event": {"const": "bet_cancel", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "BetSettlementAccountingEvent": {"properties": {"data": {"$ref": "#/components/schemas/BetSettlementData"}, "event": {"const": "bet_settlement", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "BetSettlementData": {"properties": {"accountingId": {"description": "Stable accounting identity shared by the live stream and durable log.", "pattern": "^[0-9a-f]{32}$", "type": "string"}, "certainty": {"format": "int32", "type": ["integer", "null"]}, "fixtureUrn": {"type": "string"}, "markets": {"items": {"$ref": "#/components/schemas/SettledMarket"}, "type": "array"}, "producedAt": {"format": "int64", "type": "integer"}, "sentAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}}, "required": ["accountingId", "fixtureUrn", "markets", "producedAt", "sentAt"], "type": "object"}, "BetSettlementEvent": {"properties": {"data": {"$ref": "#/components/schemas/BetSettlementData"}, "event": {"const": "bet_settlement", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "BetStopData": {"allOf": [{"$ref": "#/components/schemas/FixtureEventData"}, {"properties": {"markets": {"items": {"$ref": "#/components/schemas/LineRef"}, "type": "array"}, "producedAt": {"format": "int64", "type": "integer"}, "reason": {"format": "int32", "type": ["integer", "null"]}, "scope": {"enum": ["fixture", "markets"], "type": "string"}, "sportUrn": {"type": ["null", "string"]}, "status": {"enum": ["handed_over", "suspended"], "type": "string"}}, "type": "object"}]}, "BetStopEvent": {"properties": {"data": {"$ref": "#/components/schemas/BetStopData"}, "event": {"const": "bet_stop", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "Cancel": {"allOf": [{"$ref": "#/components/schemas/AccountingEvent"}, {"properties": {"data": {"$ref": "#/components/schemas/BetCancelData"}}, "type": "object"}]}, "CancelledMarket": {"properties": {"extendedSpecifiers": {"additionalProperties": {"type": "string"}, "type": ["null", "object"]}, "line": {"type": "string"}, "marketId": {"format": "int32", "type": "integer"}, "outcomeIds": {"items": {"type": "string"}, "type": "array"}, "specifiers": {"additionalProperties": {"type": "string"}, "type": "object"}, "voidReason": {"format": "int32", "type": ["integer", "null"]}}, "required": ["line", "marketId", "outcomeIds", "specifiers"], "type": "object"}, "FeedHealth": {"description": "Delivery transport liveness for a fixture phase. Both phase labels share the same routed stream and report the same status.", "properties": {"feed": {"enum": ["live", "prematch"], "type": "string"}, "status": {"description": "up means a credible subscribed heartbeat arrived within 20 seconds; down means no such heartbeat or a lost subscription. This does not certify fixtures, active prices, upstream freshness or snapshot completeness.", "enum": ["down", "up"], "type": "string"}}, "required": ["feed", "status"], "type": "object"}, "FixtureAccounting": {"properties": {"asOf": {"format": "int64", "type": "integer"}, "complete": {"description": "false means leave those bets unresolved; retained partial history cannot certify repair.", "type": "boolean"}, "fixtureUrn": {"type": "string"}, "lines": {"items": {"$ref": "#/components/schemas/AccountingLine"}, "type": "array"}, "sportUrn": {"type": ["null", "string"]}}, "required": ["asOf", "complete", "fixtureUrn", "lines"], "type": "object"}, "FixtureAccountingResponse": {"properties": {"fixtures": {"items": {"$ref": "#/components/schemas/FixtureAccounting"}, "type": "array"}}, "required": ["fixtures"], "type": "object"}, "FixtureChangeData": {"allOf": [{"$ref": "#/components/schemas/FixtureEventData"}, {"properties": {"changeType": {"enum": ["competitors", "coverage", "format", "other", "start_time", "status", "venue"], "type": "string"}, "lastModified": {"format": "int64", "type": "integer"}, "nextStartTime": {"format": "int64", "type": ["integer", "null"]}, "producedAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}}, "type": "object"}]}, "FixtureChangeEvent": {"properties": {"data": {"$ref": "#/components/schemas/FixtureChangeData"}, "event": {"const": "fixture_change", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "FixtureEventData": {"properties": {"fixtureUrn": {"type": "string"}, "sentAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}}, "type": "object"}, "FixtureOdds": {"properties": {"fixtureUrn": {"type": "string"}, "lastEventId": {"type": ["null", "string"]}, "markets": {"items": {"$ref": "#/components/schemas/MarketLine"}, "type": "array"}, "matchStatus": {"oneOf": [{"$ref": "#/components/schemas/MatchStatus"}, {"type": "null"}]}, "sportUrn": {"type": ["null", "string"]}, "updatedAt": {"format": "int64", "type": "integer"}}, "required": ["fixtureUrn", "markets", "updatedAt"], "type": "object"}, "FixtureRemovedData": {"allOf": [{"$ref": "#/components/schemas/FixtureEventData"}, {"properties": {"producedAt": {"format": "int64", "type": "integer"}, "reason": {"enum": ["ended", "expired"], "type": "string"}, "sportUrn": {"type": ["null", "string"]}}, "type": "object"}]}, "FixtureRemovedEvent": {"properties": {"data": {"$ref": "#/components/schemas/FixtureRemovedData"}, "event": {"const": "fixture_removed", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "FixtureSnapshotData": {"allOf": [{"$ref": "#/components/schemas/FixtureEventData"}, {"properties": {"fixture": {"$ref": "#/components/schemas/FixtureOdds"}, "reason": {"enum": ["snapshot", "sport_resolved"], "type": "string"}, "sportUrn": {"type": ["null", "string"]}}, "type": "object"}]}, "FixtureSnapshotEvent": {"properties": {"data": {"$ref": "#/components/schemas/FixtureSnapshotData"}, "event": {"const": "fixture_snapshot", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "HomeAway": {"properties": {"away": {"format": "int32", "type": "integer"}, "home": {"format": "int32", "type": "integer"}}, "required": ["away", "home"], "type": "object"}, "LineRef": {"properties": {"extendedSpecifiers": {"additionalProperties": {"type": "string"}, "type": ["null", "object"]}, "line": {"type": "string"}, "marketId": {"format": "int32", "type": "integer"}, "specifiers": {"additionalProperties": {"type": "string"}, "type": "object"}}, "required": ["line", "marketId", "specifiers"], "type": "object"}, "MarketLine": {"properties": {"extendedSpecifiers": {"additionalProperties": {"type": "string"}, "type": ["null", "object"]}, "line": {"type": "string"}, "marketId": {"format": "int32", "type": "integer"}, "outcomes": {"items": {"$ref": "#/components/schemas/OutcomeOdds"}, "type": "array"}, "specifiers": {"additionalProperties": {"type": "string"}, "type": "object"}, "status": {"enum": ["active", "cancelled", "handed_over", "inactive", "settled", "suspended"], "type": "string"}, "stopReason": {"format": "int32", "type": ["integer", "null"]}}, "required": ["line", "marketId", "outcomes", "specifiers", "status"], "type": "object"}, "MatchClock": {"properties": {"minute": {"format": "int32", "type": ["integer", "null"]}, "seconds": {"format": "int32", "type": ["integer", "null"]}}, "type": "object"}, "MatchStatus": {"properties": {"awayScore": {"format": "int32", "type": ["integer", "null"]}, "clock": {"oneOf": [{"$ref": "#/components/schemas/MatchClock"}, {"type": "null"}]}, "corners": {"oneOf": [{"$ref": "#/components/schemas/HomeAway"}, {"type": "null"}]}, "homeScore": {"format": "int32", "type": ["integer", "null"]}, "periodScores": {"items": {"$ref": "#/components/schemas/PeriodScore"}, "type": ["array", "null"]}, "redCards": {"oneOf": [{"$ref": "#/components/schemas/HomeAway"}, {"type": "null"}]}, "status": {"enum": ["abandoned", "cancelled", "closed", "delayed", "ended", "interrupted", "live", "not_started", "postponed", "suspended", "unknown"], "type": ["null", "string"]}, "statusCode": {"format": "int32", "type": ["integer", "null"]}, "yellowCards": {"oneOf": [{"$ref": "#/components/schemas/HomeAway"}, {"type": "null"}]}}, "type": "object"}, "OddsChangeData": {"allOf": [{"$ref": "#/components/schemas/FixtureEventData"}, {"properties": {"markets": {"items": {"$ref": "#/components/schemas/MarketLine"}, "type": "array"}, "matchStatus": {"oneOf": [{"$ref": "#/components/schemas/MatchStatus"}, {"type": "null"}]}, "producedAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}}, "type": "object"}]}, "OddsChangeEvent": {"properties": {"data": {"$ref": "#/components/schemas/OddsChangeData"}, "event": {"const": "odds_change", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "OddsSnapshot": {"properties": {"complete": {"type": "boolean"}, "cut": {"type": "string"}, "fixtures": {"items": {"$ref": "#/components/schemas/FixtureOdds"}, "type": "array"}}, "required": ["complete", "cut", "fixtures"], "type": "object"}, "OddsStatus": {"properties": {"feeds": {"items": {"$ref": "#/components/schemas/FeedHealth"}, "type": "array"}, "lastOddsAt": {"format": "int64", "type": ["integer", "null"]}, "liveFixtures": {"format": "int32", "type": "integer"}, "warm": {"enum": ["complete", "partial", "warming"], "type": "string"}}, "required": ["feeds", "liveFixtures", "warm"], "type": "object"}, "OddsStreamEvent": {"description": "One SSE event; the stream is a sequence; data is the JSON document of the named schema.", "discriminator": {"mapping": {"alive": "#/components/schemas/AliveEvent", "bet_cancel": "#/components/schemas/BetCancelEvent", "bet_settlement": "#/components/schemas/BetSettlementEvent", "bet_stop": "#/components/schemas/BetStopEvent", "fixture_change": "#/components/schemas/FixtureChangeEvent", "fixture_removed": "#/components/schemas/FixtureRemovedEvent", "fixture_snapshot": "#/components/schemas/FixtureSnapshotEvent", "odds_change": "#/components/schemas/OddsChangeEvent", "rollback_bet_cancel": "#/components/schemas/RollbackBetCancelEvent", "rollback_bet_settlement": "#/components/schemas/RollbackBetSettlementEvent", "snapshot_complete": "#/components/schemas/SnapshotCompleteEvent", "snapshot_start": "#/components/schemas/SnapshotStartEvent"}, "propertyName": "event"}, "oneOf": [{"$ref": "#/components/schemas/AliveEvent"}, {"$ref": "#/components/schemas/BetCancelEvent"}, {"$ref": "#/components/schemas/BetSettlementEvent"}, {"$ref": "#/components/schemas/BetStopEvent"}, {"$ref": "#/components/schemas/FixtureChangeEvent"}, {"$ref": "#/components/schemas/FixtureRemovedEvent"}, {"$ref": "#/components/schemas/FixtureSnapshotEvent"}, {"$ref": "#/components/schemas/OddsChangeEvent"}, {"$ref": "#/components/schemas/RollbackBetCancelEvent"}, {"$ref": "#/components/schemas/RollbackBetSettlementEvent"}, {"$ref": "#/components/schemas/SnapshotCompleteEvent"}, {"$ref": "#/components/schemas/SnapshotStartEvent"}]}, "Operation": {"properties": {"id": {"type": "string"}, "step": {"format": "int32", "type": "integer"}, "undoes": {"type": ["null", "string"]}}, "required": ["id", "step"], "type": "object"}, "OutcomeOdds": {"properties": {"active": {"type": "boolean"}, "odds": {"type": ["null", "number"]}, "outcomeId": {"type": "string"}}, "required": ["active", "outcomeId"], "type": "object"}, "PeriodScore": {"properties": {"awayScore": {"format": "int32", "type": ["integer", "null"]}, "homeScore": {"format": "int32", "type": ["integer", "null"]}, "number": {"format": "int32", "type": "integer"}, "statusCode": {"format": "int32", "type": "integer"}}, "required": ["number", "statusCode"], "type": "object"}, "RollbackBetCancelAccountingEvent": {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetCancelData"}, "event": {"const": "rollback_bet_cancel", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "RollbackBetCancelData": {"properties": {"accountingId": {"description": "Stable accounting identity shared by the live stream and durable log.", "pattern": "^[0-9a-f]{32}$", "type": "string"}, "fixtureUrn": {"type": "string"}, "from": {"format": "int64", "type": ["integer", "null"]}, "markets": {"items": {"$ref": "#/components/schemas/LineRef"}, "type": "array"}, "operation": {"oneOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}]}, "producedAt": {"format": "int64", "type": "integer"}, "sentAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}, "to": {"format": "int64", "type": ["integer", "null"]}}, "required": ["accountingId", "fixtureUrn", "markets", "producedAt", "sentAt"], "type": "object"}, "RollbackBetCancelEvent": {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetCancelData"}, "event": {"const": "rollback_bet_cancel", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "RollbackBetSettlementAccountingEvent": {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetSettlementData"}, "event": {"const": "rollback_bet_settlement", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "RollbackBetSettlementData": {"properties": {"accountingId": {"description": "Stable accounting identity shared by the live stream and durable log.", "pattern": "^[0-9a-f]{32}$", "type": "string"}, "fixtureUrn": {"type": "string"}, "markets": {"items": {"$ref": "#/components/schemas/LineRef"}, "type": "array"}, "operation": {"oneOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}]}, "producedAt": {"format": "int64", "type": "integer"}, "sentAt": {"format": "int64", "type": "integer"}, "sportUrn": {"type": ["null", "string"]}}, "required": ["accountingId", "fixtureUrn", "markets", "producedAt", "sentAt"], "type": "object"}, "RollbackBetSettlementEvent": {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetSettlementData"}, "event": {"const": "rollback_bet_settlement", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "RollbackCancel": {"allOf": [{"$ref": "#/components/schemas/AccountingEvent"}, {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetCancelData"}}, "type": "object"}]}, "RollbackSettlement": {"allOf": [{"$ref": "#/components/schemas/AccountingEvent"}, {"properties": {"data": {"$ref": "#/components/schemas/RollbackBetSettlementData"}}, "type": "object"}]}, "SettledMarket": {"properties": {"extendedSpecifiers": {"additionalProperties": {"type": "string"}, "type": ["null", "object"]}, "line": {"type": "string"}, "makeup": {"type": ["null", "number"]}, "marketId": {"format": "int32", "type": "integer"}, "outcomes": {"items": {"$ref": "#/components/schemas/SettledOutcome"}, "type": "array"}, "specifiers": {"additionalProperties": {"type": "string"}, "type": "object"}, "voidReason": {"format": "int32", "type": ["integer", "null"]}}, "required": ["line", "marketId", "outcomes", "specifiers"], "type": "object"}, "SettledOutcome": {"properties": {"deadHeatFactor": {"type": ["null", "number"]}, "outcomeId": {"type": "string"}, "result": {"enum": ["half_lost", "half_won", "lose_quarter", "lost", "void", "win_quarter", "won"], "type": "string"}, "voidFactor": {"type": ["null", "number"]}}, "required": ["outcomeId", "result"], "type": "object"}, "Settlement": {"allOf": [{"$ref": "#/components/schemas/AccountingEvent"}, {"properties": {"data": {"$ref": "#/components/schemas/BetSettlementData"}}, "type": "object"}]}, "SnapshotCompleteData": {"properties": {"fixtures": {"format": "int32", "type": "integer"}, "sentAt": {"format": "int64", "type": "integer"}}, "required": ["fixtures", "sentAt"], "type": "object"}, "SnapshotCompleteEvent": {"properties": {"data": {"$ref": "#/components/schemas/SnapshotCompleteData"}, "event": {"const": "snapshot_complete", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "SnapshotStartData": {"properties": {"reason": {"enum": ["connect", "overflow", "partial", "resume_gap", "warmed"], "type": "string"}, "sentAt": {"format": "int64", "type": "integer"}}, "required": ["reason", "sentAt"], "type": "object"}, "SnapshotStartEvent": {"properties": {"data": {"$ref": "#/components/schemas/SnapshotStartData"}, "event": {"const": "snapshot_start", "type": "string"}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object"}, "SseEmitter": {"properties": {"timeout": {"format": "int64", "type": "integer"}}, "type": "object"}, "WarmingError": {"properties": {"error": {"type": "string"}, "retryAfterSeconds": {"format": "int32", "type": "integer"}}, "required": ["error", "retryAfterSeconds"], "type": "object"}, "Stream_alive": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/AliveData"}}, "event": {"const": "alive", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "alive", "description": "Every ten seconds. Refresh the watchdog and check each feed status.", "examples": [{"data": "{\n  \"feeds\": [\n    {\n      \"feed\": \"live\",\n      \"status\": \"up\"\n    },\n    {\n      \"feed\": \"prematch\",\n      \"status\": \"up\"\n    }\n  ],\n  \"sentAt\": 1800000000000\n}", "event": "alive"}]}, "Stream_bet_cancel": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/BetCancelData"}}, "event": {"const": "bet_cancel", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "bet_cancel", "description": "A cancellation arrives. Wake accounting; remove lines only for an untimed full cancel.", "examples": [{"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde1\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"from\": 1799999995000,\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomeIds\": [\n        \"1\"\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\",\n  \"to\": 1800000000000\n}", "event": "bet_cancel", "id": "demo.42"}]}, "Stream_bet_settlement": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/BetSettlementData"}}, "event": {"const": "bet_settlement", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "bet_settlement", "description": "A settlement arrives. Remove settled price lines; wake the accounting reader.", "examples": [{"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcdef\",\n  \"certainty\": 1,\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomes\": [\n        {\n          \"deadHeatFactor\": 0.5,\n          \"outcomeId\": \"1\",\n          \"result\": \"won\",\n          \"voidFactor\": 0.5\n        }\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "bet_settlement", "id": "demo.42"}]}, "Stream_bet_stop": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/BetStopData"}}, "event": {"const": "bet_stop", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "bet_stop", "description": "Betting stops. Suspend the fixture or the listed market lines.", "examples": [{"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"reason\": 900,\n  \"scope\": \"markets\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\",\n  \"status\": \"suspended\"\n}", "event": "bet_stop", "id": "demo.42"}]}, "Stream_fixture_change": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/FixtureChangeData"}}, "event": {"const": "fixture_change", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "fixture_change", "description": "Metadata changes. Refresh catalog metadata and apply nextStartTime.", "examples": [{"data": "{\n  \"changeType\": \"status\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"lastModified\": 1800000000000,\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_change", "id": "demo.42"}]}, "Stream_fixture_removed": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/FixtureRemovedData"}}, "event": {"const": "fixture_removed", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "fixture_removed", "description": "A fixture leaves the book. Remove the fixture.", "examples": [{"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"producedAt\": 1800000000000,\n  \"reason\": \"ended\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_removed", "id": "demo.42"}]}, "Stream_fixture_snapshot": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/FixtureSnapshotData"}}, "event": {"const": "fixture_snapshot", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "fixture_snapshot", "description": "During replacement or fixture discovery. Replace this fixture; stage it during replacement.", "examples": [{"data": "{\n  \"fixture\": {\n    \"fixtureUrn\": \"sportlive:match:9001\",\n    \"markets\": [\n      {\n        \"extendedSpecifiers\": {\n          \"score\": \"0:0\"\n        },\n        \"line\": \"hcp=-0.5|total=2.5\",\n        \"marketId\": 1,\n        \"outcomes\": [\n          {\n            \"active\": true,\n            \"odds\": 1.85,\n            \"outcomeId\": \"1\"\n          }\n        ],\n        \"specifiers\": {\n          \"hcp\": \"-0.5\",\n          \"total\": \"2.5\"\n        },\n        \"status\": \"active\"\n      }\n    ],\n    \"matchStatus\": {\n      \"awayScore\": 0,\n      \"homeScore\": 0,\n      \"status\": \"live\"\n    },\n    \"sportUrn\": \"sportlive:sport:2\",\n    \"updatedAt\": 1800000000000\n  },\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"reason\": \"snapshot\",\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "fixture_snapshot"}]}, "Stream_odds_change": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/OddsChangeData"}}, "event": {"const": "odds_change", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "odds_change", "description": "Prices or match state change. Merge market lines, outcomes and matchStatus. Only changed lines are listed; an unchanged book makes no event.", "examples": [{"data": "{\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"outcomes\": [\n        {\n          \"active\": true,\n          \"odds\": 1.85,\n          \"outcomeId\": \"1\"\n        }\n      ],\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      },\n      \"status\": \"active\"\n    }\n  ],\n  \"matchStatus\": {\n    \"awayScore\": 0,\n    \"homeScore\": 0,\n    \"status\": \"live\"\n  },\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "odds_change", "id": "demo.42"}]}, "Stream_rollback_bet_cancel": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/RollbackBetCancelData"}}, "event": {"const": "rollback_bet_cancel", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "rollback_bet_cancel", "description": "A cancellation is undone. Wake accounting to recover the correction.", "examples": [{"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde3\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "rollback_bet_cancel", "id": "demo.42"}]}, "Stream_rollback_bet_settlement": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/RollbackBetSettlementData"}}, "event": {"const": "rollback_bet_settlement", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "rollback_bet_settlement", "description": "A settlement is undone. Wake accounting to recover the correction.", "examples": [{"data": "{\n  \"accountingId\": \"0123456789abcdef0123456789abcde2\",\n  \"fixtureUrn\": \"sportlive:match:9001\",\n  \"markets\": [\n    {\n      \"extendedSpecifiers\": {\n        \"score\": \"0:0\"\n      },\n      \"line\": \"hcp=-0.5|total=2.5\",\n      \"marketId\": 1,\n      \"specifiers\": {\n        \"hcp\": \"-0.5\",\n        \"total\": \"2.5\"\n      }\n    }\n  ],\n  \"producedAt\": 1800000000000,\n  \"sentAt\": 1800000000000,\n  \"sportUrn\": \"sportlive:sport:2\"\n}", "event": "rollback_bet_settlement", "id": "demo.42"}]}, "Stream_snapshot_complete": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/SnapshotCompleteData"}}, "event": {"const": "snapshot_complete", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "snapshot_complete", "description": "Replacement finishes. Publish the staged book atomically, then save the id.", "examples": [{"data": "{\n  \"fixtures\": 1,\n  \"sentAt\": 1800000000000\n}", "event": "snapshot_complete", "id": "demo.42"}]}, "Stream_snapshot_start": {"properties": {"data": {"type": "string", "description": "JSON data payload. Decode once before applying this event.", "contentMediaType": "application/json", "contentSchema": {"$ref": "#/components/schemas/SnapshotStartData"}}, "event": {"const": "snapshot_start", "type": "string", "description": "The SSE event name selects the payload model."}, "id": {"description": "Opaque resume id; absent for unlogged events; empty resets the client cursor.", "type": "string"}}, "required": ["data", "event"], "type": "object", "title": "snapshot_start", "description": "Replacement starts. Clear the cursor; begin a new staged book.", "examples": [{"data": "{\n  \"reason\": \"connect\",\n  \"sentAt\": 1800000000000\n}", "event": "snapshot_start", "id": ""}]}}, "securitySchemes": {"ApiKey": {"description": "Send your API key in the X-API-Key header on every call. These APIs take no Authorization header.", "in": "header", "name": "X-API-Key", "type": "apiKey"}}}, "x-tagGroups": [{"name": "Catalog", "tags": ["Catalog"]}, {"name": "Odds", "tags": ["Odds"]}, {"name": "Accounting", "tags": ["Accounting"]}]}