API Reference
One REST API for live and historical odds from 55+ bookmakers across 8 countries — opening lines, closing lines, alternate ladders, sharpness ratings and stats. JSON in, JSON out.
The base URL for all requests is:
https://api.vividodds.com/v1
Every response is JSON. All odds are decimal. Timestamps are ISO 8601 (UTC). Get a key from the dashboard and you can make your first call in under a minute.
Quickstart
# every book's price for one event, opening + closing curl https://api.vividodds.com/v1/odds/OYIoIMcD?markets=total \ -H "Authorization: Bearer vo_live_..."
const res = await fetch( "https://api.vividodds.com/v1/odds/OYIoIMcD?markets=total", { headers: { Authorization: "Bearer vo_live_..." } } ); const data = await res.json();
import requests r = requests.get( "https://api.vividodds.com/v1/odds/OYIoIMcD", params={"markets": "total"}, headers={"Authorization": "Bearer vo_live_..."}, ) data = r.json()
Authentication
Authenticate every request with your secret key in the Authorization header as a bearer token. Keys are created and rotated in the dashboard. Never expose a secret key in client-side code.
Authorization: Bearer vo_live_9f3c...e21a
vo_test_ return sample data and don't count against your quota. Swap to vo_live_ when you're ready.Rate limits
Limits are per key and depend on your plan. Every response includes your current usage in the headers below. A 429 means you've hit the ceiling — back off and retry after the reset.
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Calls allowed in the current window. |
| X-RateLimit-Remaining | Calls left in the current window. |
| X-RateLimit-Reset | Unix time when the window resets. |
Pagination
List endpoints return up to 100 items per page. Pass cursor from a response's next field to fetch the following page; a null next means you've reached the end.
Events
List fixtures and finished events with results. Filter by sport, league, date range and status.
| Parameter | Description |
|---|---|
| sport string | soccer · tennis · basketball · hockey · baseball |
| league string | League id, e.g. epl. Optional. |
| date string | Single day YYYY-MM-DD, or use from/to. |
| status string | scheduled · live · finished |
{
"data": [
{
"id": "OYIoIMcD",
"sport": "tennis",
"league": "atp",
"home": "Sinner", "away": "Alcaraz",
"startsAt": "2026-07-04T13:30:00Z",
"status": "finished",
"result": { "home": 2, "away": 1, "total": 27 }
}
],
"next": "c_8f2a..."
}Odds
Every book's current and opening price for an event, plus the no-vig consensus fair and the sharpest book. Ask for the markets and countries you want.
| Parameter | Description |
|---|---|
| markets string | Comma-separated: ml, total, spread, btts. Default all. |
| books string | Filter to specific books, e.g. bet365,winamax. Default all. |
| countries string | Country markets, e.g. it,fr,es. Default all. |
{
"event": "Sinner v Alcaraz",
"market": "total_games", "line": 22.5,
"fair": { "over": 1.94, "under": 1.92 },
"sharpest": "betfair",
"books": [
{ "book": "bet365", "country": "it", "open": 1.90, "now": 1.95 },
{ "book": "winamax", "country": "fr", "open": 1.85, "now": 2.02 }
]
}Historical odds
Bulk opening + closing odds across books, back to 2014. The dataset for backtesting a whole season or measuring CLV at scale. Paginated; also available as a one-time bulk export.
| Parameter | Description |
|---|---|
| sport stringrequired | Sport to pull. |
| from · to daterequired | Date range, YYYY-MM-DD. |
| market string | e.g. total. Optional. |
| book string | Restrict to one book. Optional. |
Closing-line value
The opening → closing journey for every selection, with the no-vig fair and the CLV of taking the open. Score any bet against the market's own closing consensus.
{
"event": "Sinner v Alcaraz",
"selections": [
{ "market": "total", "side": "over", "line": 22.5,
"open": 1.99, "close": 1.94,
"fairClose": 1.90, "clv": 0.026 }
]
}Match stats
Match and player statistics for an event — shots, cards, possession and sport-specific box scores — for modelling and settlement.
Errors
VividOdds uses conventional HTTP status codes. Errors return a JSON body with a machine-readable code and a human-readable message.
| Status | Meaning |
|---|---|
| 200 | OK. |
| 400 | Bad request — a parameter is missing or malformed. |
| 401 | Invalid or missing API key. |
| 404 | No event or resource with that id. |
| 429 | Rate limit reached — retry after the reset. |
| 5xx | Something failed on our side. Safe to retry with backoff. |
{
"error": {
"code": "invalid_parameter",
"message": "Unknown sport 'crickett'. Try soccer, tennis, basketball."
}
}SDKs
Official libraries wrap auth, retries and pagination. Generated from our OpenAPI spec, so they're always in sync with the API.
npm install vividodds import { VividOdds } from "vividodds"; const vo = new VividOdds("vo_live_..."); const odds = await vo.odds("OYIoIMcD", { markets: ["total"] });
pip install vividodds from vividodds import VividOdds vo = VividOdds("vo_live_...") odds = vo.odds("OYIoIMcD", markets=["total"])