Getting started
Quickstart
Go from a new account to bet365 prices in four calls. You need a token and a terminal, Python or Node.js.
Step 1
Get a token
Sign in, open the dashboard and copy your API token. Keep it in an environment variable rather than in your code.
export ODDS_DATA_API_TOKEN="YOUR-TOKEN"Step 2
List in-play events
Ask for every soccer event in play right now with
sport_id=1. Each event has ourid, the bet365 fixture id inbet365_id, the score inssand the clock intimer.curl "https://api.odds-data-api.com/v3/events/inplay?sport_id=1&token=$ODDS_DATA_API_TOKEN"application/json{ "success": 1, "pager": { "page": 1, "per_page": 1000, "total": 2 }, "results": [ { "id": "8204771", "sport_id": "1", "time": "1789237200", "time_status": "1", "league": { "id": "10041282", "name": "England Premier League", "cc": "gb" }, "home": { "id": "10204", "name": "Brentford", "image_id": null, "cc": "gb" }, "away": { "id": "10218", "name": "Everton", "image_id": null, "cc": "gb" }, "ss": "2-1", "scores": { "1": { "home": "1", "away": "0" }, "2": { "home": "2", "away": "1" } }, "timer": { "tm": 67, "ts": 12, "tt": "1", "ta": 0, "md": 1 }, "bet365_id": "158204771" }, { "id": "8212001", "sport_id": "1", "time": "1789241100", "time_status": "1", "league": { "id": "10090001", "name": "Esoccer Battle - 8 mins play", "cc": null }, "home": { "id": "90001", "name": "Liverpool (Marlin) Esports", "image_id": null, "cc": null }, "away": { "id": "90002", "name": "Real Madrid (Cobalt) Esports", "image_id": null, "cc": null }, "ss": "2-3", "timer": { "tm": 5, "ts": 41, "tt": "1", "ta": 0, "md": 1 }, "bet365_id": "158212001" } ] }The second result is an Esoccer event: it is listed under Soccer too. Leave it out with
skip_esports=1on the endpoints that take it. See Esports.Step 3
View one event
Pass the
idfrom step 2 asevent_idto get stats, timeline, stadium, referee and managers.curl "https://api.odds-data-api.com/v1/event/view?event_id=8204771&token=$ODDS_DATA_API_TOKEN"application/json{ "success": 1, "results": [ { "id": "8204771", "sport_id": "1", "time": "1789237200", "time_status": "1", "league": { "id": "10041282", "name": "England Premier League", "cc": "gb" }, "home": { "id": "10204", "name": "Brentford", "image_id": null, "cc": "gb" }, "away": { "id": "10218", "name": "Everton", "image_id": null, "cc": "gb" }, "ss": "2-1", "scores": { "1": { "home": "1", "away": "0" }, "2": { "home": "2", "away": "1" } }, "timer": { "tm": 67, "ts": 12, "tt": "1", "ta": 0, "md": 1 }, "bet365_id": "158204771", "stats": { "attacks": [ "88", "61" ], "dangerous_attacks": [ "44", "29" ], "possession_rt": [ "57", "43" ], "on_target": [ "6", "3" ], "off_target": [ "7", "5" ], "corners": [ "6", "3" ], "yellowcards": [ "2", "1" ] }, "extra": { "home_manager": { "id": "53463", "name": "Tomás Duarte", "cc": "pt" }, "away_manager": { "id": "1152", "name": "Hugo Keller", "cc": "de" }, "referee": { "id": "107059", "name": "Chris Kavanagh", "cc": "gb" }, "stadium_data": { "id": "606", "name": "Gtech Community Stadium", "city": "London", "country": "England" }, "round": "4" }, "events": [ { "id": "69731159", "text": "15' - 1st Goal - (Brentford) -" }, { "id": "69731190", "text": "58' - 3rd Goal - (Everton) -" } ], "has_lineup": 1, "inplay_created_at": "1789236300", "inplay_updated_at": "1789241232" } ] }Step 4
Read bet365 odds
Pass
bet365_idfrom step 2 asFIto the Bet365 API. PreMatch Odds groups every market in sections:main,asian_lines,goals,halfandothers.curl "https://api.odds-data-api.com/v4/bet365/prematch?FI=158204771&token=$ODDS_DATA_API_TOKEN"application/json{ "success": 1, "results": [ { "FI": "158204771", "event_id": "8204771", "main": { "updated_at": "1789236000", "key": "main", "sp": { "full_time_result": { "id": "40", "name": "Full Time Result", "odds": [ { "id": "962056610", "odds": "2.45", "name": "1" }, { "id": "962056617", "odds": "3.60", "name": "Draw" }, { "id": "962056618", "odds": "2.80", "name": "2" } ] } } }, "asian_lines": { "updated_at": "1789236000", "key": "asian_lines", "sp": {} }, "goals": { "updated_at": "1789236000", "key": "goals", "sp": {} }, "half": { "updated_at": "1789236000", "key": "half", "sp": {} }, "others": [] } ] }Pre-match prices stop updating at kickoff. For a live event, read the current prices from Bet365 Inplay Event with the same
FI. Market keys are listed in Market keys.
Poll within your limit
In-play prices change every few seconds. Poll on a fixed interval that fits your hourly limit, and stop polling an event once its time_status is final.
- 3,600 requests per hour is one request per second across all the events you follow.
- Read
X-RateLimit-Remainingon every response and slow down before it reaches zero. - On
TOO_MANY_REQUESTS, wait untilX-RateLimit-Resetinstead of retrying at once.
import os, time, requests
API = "https://api.odds-data-api.com"
TOKEN = os.environ["ODDS_DATA_API_TOKEN"]
def get(path, **params):
while True:
res = requests.get(API + path, params={**params, "token": TOKEN})
data = res.json()
if data["success"] == 1:
return data
if data["error"] == "TOO_MANY_REQUESTS":
# Wait until the hourly window resets, then retry.
reset = int(res.headers["X-RateLimit-Reset"])
time.sleep(max(reset - time.time(), 1))
continue
raise RuntimeError(data["error"] + " " + data.get("error_detail", ""))
while True:
event = get("/v1/bet365/event", FI="158204771")
# Update your model with event["results"]
time.sleep(2)Limits per plan and the response headers are in Rate limits.
