Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/odds-api-catalog-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Odds Catalog API
description: 'The Odds API V1 provides sports and racing events, bookmaker odds, exchange and prediction-market order books,
live price updates, betting opportunity snapshots, and result lookups for production integrations.'
version: 1.0.0
license:
name: Proprietary
url: https://odds-api.net
x-workflow-examples:
- name: positive_ev_request
summary: Find positive EV bets for a league.
steps:
- GET /v1/events?sport=rugby-league&league=NRL
- GET /v1/bets/snapshot?strategies=pos_ev
- Use response timestamps and stake/risk controls before showing user-facing picks.
- name: arbitrage_request
summary: Find arbitrage opportunities across allowed bookmakers.
steps:
- GET /v1/bookmakers
- GET /v1/bets/snapshot?strategies=arbitrage
- Show execution-risk caveats; never present arbitrage as guaranteed after limits, voids, or delays.
- name: odds_history_request
summary: Get line movement for a market.
steps:
- GET /v1/events/{event_id}/odds/snapshot
- Pick a selection_key from an odds line.
- GET /v1/events/{event_id}/odds/history?selection_key=...
- name: prediction_market_orderbook_request
summary: Read and follow a curated prediction-market order book.
steps:
- GET /v1/events?sport=basketball&league=NBA
- GET /v1/events/{event_id}/prediction-markets/orderbook/snapshot?providers=polymarket,kalshi&depth=3
- Connect to the matching /stream or /ws route with since=<snapshot resume>.
x-responsible-gambling: Do not present betting outcomes as risk-free. Always mention execution risk, stale prices, bookmaker limits, voids, delays, and jurisdictional availability in user-facing products.
x-production-integration:
recommended_flow:
- Authenticate backend requests with X-API-Key.
- Discover sports, leagues, and bookmakers before storing local filters.
- Page sports or racing events with limit and cursor.
- Fetch odds snapshots for initial state. Explicit bookmaker filters are complete in one response; otherwise follow bookmaker-complete pages until complete=true. Persist as_of_ts_ms, ttl_seconds, and resume.
- Use SSE or WebSocket streams for realtime updates and reconnect with since=<last_resume>.
- Use history endpoints for line movement and results endpoints after events finish.
recommended_polling_intervals:
catalog_metadata: 6-24h
sports_events: 5-15m, or 1-5m for active leagues and near-start windows
racing_events: 1-5m with narrow time windows
odds_snapshots_without_streams: 60-120s, or 15-30s for priority events with strict quota controls
betting_opportunity_snapshots: 30-120s depending on alert urgency
results_after_start: 1-5m until settled, then back off
stream_reconnects:
- Snapshot first, then connect to /stream or /ws with matching filters.
- Apply delta messages idempotently and persist the newest resume token.
- Use heartbeat messages as liveness checks.
- Reconnect with jittered exponential backoff and since=<last_resume>.
- Reload the snapshot when a resync message indicates the resume token is unavailable.
rate_limit_backoff:
- Honor Retry-After on 429 when present.
- Otherwise start around 2 seconds and double up to about 60 seconds with jitter.
- Use X-RateLimit-* response headers when present to tune callers.
- Use /usage to detect monthly API-credit quota exhaustion and stop retry loops.
cache_strategy:
- Cache by endpoint path, event ID, normalized filters, page cursor, and product context.
- Respect ttl_seconds when present and always surface as_of_ts_ms.
- Use streams to update hot caches and reload snapshots after resync or parse failure.
- Prefer stale-while-revalidate displays with a visible timestamp.
failure_modes:
- 400 invalid request shape, cursor, timestamp, or filter.
- 401 missing or invalid API key.
- 403 key lacks plan, product, bookmaker, stream, racing, or strategy access.
- 404 event, race, result, or selection is unavailable.
- 429 rate limit or monthly quota exhaustion.
- 5xx transient service failure; retry with backoff and keep last good cached data marked stale.
- Stream close or resync; reconnect with since or reload the snapshot.
servers:
- url: https://api.odds-api.net/v1
description: Production V1 base URL. Set ODDS_API_BASE_URL to override it in SDKs and examples.
security:
- ApiKeyAuth: []
tags:
- name: Catalog
description: Supported sports, leagues, bookmakers, and approximate market coverage.
paths:
/sports:
get:
tags:
- Catalog
summary: 'Catalog: Sports'
operationId: sports_sports_get
security:
- ApiKeyAuth: []
parameters: []
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/StringListResponse'
'400':
description: Invalid request parameters or body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Credentials are valid but do not allow this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded.
headers:
Retry-After:
description: Seconds to wait before retrying when supplied by the limiter.
schema:
type: integer
minimum: 1
X-RateLimit-Limit:
description: Request bucket capacity for the active limiter bucket when supplied.
schema:
type: integer
X-RateLimit-Remaining:
description: Approximate remaining requests in the active limiter bucket when supplied.
schema:
type: integer
minimum: 0
X-RateLimit-Bucket:
description: Limiter bucket name that produced the response when supplied.
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitResponse'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Lists sports with event and odds coverage.
x-rate-limit-note: Handle HTTP 429 with backoff and avoid tight polling loops.
/leagues:
get:
tags:
- Catalog
summary: 'Catalog: Leagues'
operationId: leagues_leagues_get
security:
- ApiKeyAuth: []
parameters:
- name: sport
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Sport
description: Sport filter. Use `/sports` to discover supported values.
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/StringListResponse'
'400':
description: Invalid request parameters or body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Credentials are valid but do not allow this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded.
headers:
Retry-After:
description: Seconds to wait before retrying when supplied by the limiter.
schema:
type: integer
minimum: 1
X-RateLimit-Limit:
description: Request bucket capacity for the active limiter bucket when supplied.
schema:
type: integer
X-RateLimit-Remaining:
description: Approximate remaining requests in the active limiter bucket when supplied.
schema:
type: integer
minimum: 0
X-RateLimit-Bucket:
description: Limiter bucket name that produced the response when supplied.
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitResponse'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Lists available leagues. Pass `sport` to narrow the response.
x-rate-limit-note: Handle HTTP 429 with backoff and avoid tight polling loops.
/bookmakers:
get:
tags:
- Catalog
summary: 'Catalog: Bookmakers'
operationId: bookmakers_bookmakers_get
security:
- ApiKeyAuth: []
parameters:
- name: country_code
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Optional comma-separated country code filter, for example `AU` or `AU,UK`.
title: Country Code
description: Comma-separated country code filter, for example `AU` or `AU,UK`.
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/BookmakerCatalogResponse'
examples:
default:
summary: 'Catalog: Bookmakers'
value:
items:
- bookmaker: bet365
country_codes:
- AU
- UK
- bookmaker: pinnacle
country_codes:
- US
'400':
description: Invalid request parameters or body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Credentials are valid but do not allow this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded.
headers:
Retry-After:
description: Seconds to wait before retrying when supplied by the limiter.
schema:
type: integer
minimum: 1
X-RateLimit-Limit:
description: Request bucket capacity for the active limiter bucket when supplied.
schema:
type: integer
X-RateLimit-Remaining:
description: Approximate remaining requests in the active limiter bucket when supplied.
schema:
type: integer
minimum: 0
X-RateLimit-Bucket:
description: Limiter bucket name that produced the response when supplied.
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitResponse'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Lists active bookmakers accepted by bookmaker filters across odds and betting endpoints. Each item includes the country codes where that bookmaker is available. Pass `country_code=AU` or `country_code=AU,UK` to filter the catalog.
x-rate-limit-note: Handle HTTP 429 with backoff and avoid tight polling loops.
/bookmakers/countries:
get:
tags:
- Catalog
summary: 'Catalog: Bookmaker countries'
operationId: bookmaker_countries_bookmakers_countries_get
security:
- ApiKeyAuth: []
parameters: []
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/BookmakerCountriesCatalogResponse'
examples:
default:
summary: 'Catalog: Bookmaker countries'
value:
items:
- country_code: AU
country: Australia
bookmakers:
- bet365
- sportsbet
- country_code: UK
country: United Kingdom
bookmakers:
- bet365
'400':
description: Invalid request parameters or body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Credentials are valid but do not allow this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded.
headers:
Retry-After:
description: Seconds to wait before retrying when supplied by the limiter.
schema:
type: integer
minimum: 1
X-RateLimit-Limit:
description: Request bucket capacity for the active limiter bucket when supplied.
schema:
type: integer
X-RateLimit-Remaining:
description: Approximate remaining requests in the active limiter bucket when supplied.
schema:
type: integer
minimum: 0
X-RateLimit-Bucket:
description: Limiter bucket name that produced the response when supplied.
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitResponse'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Lists country codes represented in the active bookmaker catalog and the bookmakers available in each country.
x-rate-limit-note: Handle HTTP 429 with backoff and avoid tight polling loops.
/coverage:
get:
tags:
- Catalog
summary: 'Catalog: Coverage'
operationId: coverage_coverage_get
security: []
parameters:
- name: bookmaker
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Canonical bookmaker filter, for example `bet365`.
title: Bookmaker
description: Canonical bookmaker filter. Use `/bookmakers` or `/coverage` to discover supported keys.
- name: sport
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Sport filter, for example `basketball`.
title: Sport
description: Sport filter. Use `/sports` to discover supported values.
- name: league
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: League filter, for example `NBA`.
title: League
description: League filter. Use `/leagues?sport=...` to discover supported values.
- name: country_code
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Optional comma-separated country code filter.
title: Country Code
description: Comma-separated country code filter, for example `AU` or `AU,UK`.
- name: lookback_days
in: query
required: false
schema:
type: integer
maximum: 90
minimum: 1
default: 30
title: Lookback Days
description: Number of days of recently observed approximate market coverage to include. Maximum is 90.
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/CoverageResponse'
examples:
default:
summary: 'Catalog: Coverage'
value:
as_of: '2026-04-29T10:25:00Z'
bookmakers:
- bookmaker: bet365
country_codes:
- AU
- UK
- bookmaker: sportsbet
country_codes:
- AU
sports:
- basketball
- rugby league
leagues:
- sport: basketball
league: NBA
- sport: rugby league
league: NRL
markets:
- bookmaker: bet365
sport: basketball
league: NBA
bet_type: moneyline
last_seen_at: '2026-04-29T10:20:00Z'
sample_event_id: '3704597661'
- bookmaker: sportsbet
sport: rugby league
league: NRL
bet_type: total
metric: tries
last_seen_at: '2026-04-29T10:18:00Z'
sample_event_id: '3704597662'
source:
markets_are_approximate: true
lookback_days: 30
'400':
description: Invalid request parameters or body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Credentials are valid but do not allow this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded.
headers:
Retry-After:
description: Seconds to wait before retrying when supplied by the limiter.
schema:
type: integer
minimum: 1
X-RateLimit-Limit:
description: Request bucket capacity for the active limiter bucket when supplied.
schema:
type: integer
X-RateLimit-Remaining:
description: Approximate remaining requests in the active limiter bucket when supplied.
schema:
type: integer
minimum: 0
X-RateLimit-Bucket:
description: Limiter bucket name that produced the response when supplied.
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitResponse'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Returns public bookmaker, sport, league, and recently observed market coverage. Market records are approximate and based on normalized odds lines seen in the configured lookback window, not a guarantee that every market is available for every event at request time.
x-rate-limit-note: Handle HTTP 429 with backoff and avoid tight polling loops.
components:
schemas:
CoverageSource:
properties:
markets_are_approximate:
type: boolean
title: Markets Are Approximate
default: true
lookback_days:
type: integer
title: Lookback Days
type: object
required:
- lookback_days
title: CoverageSource
BookmakerCountriesCatalogResponse:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/BookmakerCountryCatalogItem'
CoverageLeague:
properties:
sport:
type: string
title: Sport
league:
type: string
title: League
type: object
required:
- sport
- league
title: CoverageLeague
RateLimitResponse:
allOf:
- $ref: '#/components/schemas/ErrorResponse'
description: Rate-limit response. Retry after the window or reduce polling frequency.
BookmakerCatalogResponse:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/BookmakerCatalogItem'
CoverageResponse:
properties:
as_of:
type: string
title: As Of
bookmakers:
items:
$ref: '#/components/schemas/CoverageBookmaker'
type: array
title: Bookmakers
sports:
items:
type: string
type: array
title: Sports
leagues:
items:
$ref: '#/components/schemas/CoverageLeague'
type: array
title: Leagues
markets:
items:
$ref: '#/components/schemas/CoverageMarket'
type: array
title: Markets
source:
$ref: '#/components/schemas/CoverageSource'
type: object
required:
- as_of
- source
title: CoverageResponse
ErrorResponse:
type: object
required:
- detail
properties:
detail:
description: Human-readable error detail. FastAPI may return a string or a validation-error object.
oneOf:
- type: string
- type: object
- type: array
items:
type: object
code:
type: string
description: Optional stable error code when provided by the endpoint.
request_id:
type: string
description: Optional request identifier for support/debugging.
StringListResponse:
type: object
required:
- items
properties:
items:
type: array
items:
type: string
CoverageMarket:
properties:
bookmaker:
type: string
title: Bookmaker
sport:
type: string
title: Sport
league:
type: string
title: League
bet_type:
type: string
title: Bet Type
metric:
anyOf:
- type: string
- type: 'null'
title: Metric
period:
anyOf:
- type: string
- type: 'null'
title: Period
last_seen_at:
type: string
title: Last Seen At
sample_event_id:
type: string
title: Sample Event Id
type: object
required:
- bookmaker
- sport
- league
- bet_type
- last_seen_at
- sample_event_id
title: CoverageMarket
BookmakerCountryCatalogItem:
type: object
required:
- country_code
- bookmakers
properties:
country_code:
type: string
example: AU
country:
type: string
nullable: true
example: Australia
bookmakers:
type: array
items:
type: string
description: Canonical bookmaker identifiers active for this country code.
BookmakerCatalogItem:
type: object
required:
- bookmaker
- country_codes
properties:
bookmaker:
type: string
description: Canonical bookmaker identifier accepted by bookmaker filters.
example: bet365
country_codes:
type: array
items:
type: string
description: Country codes where this bookmaker is active, for example `AU` or `UK`.
example:
- AU
- UK
source_bookmaker:
type: string
nullable: true
description: Canonical source bookmaker when this bookmaker reuses another bookmaker's sports odds.
example: betnation
CoverageBookmaker:
properties:
bookmaker:
type: string
title: Bookmaker
country_codes:
items:
type: string
type: array
title: Country Codes
type: object
required:
- bookmaker
title: CoverageBookmaker
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: Send your API key in this header on every request.