bet365 historical odds API
Every bet365 price change we have recorded, pre-match and in-play, as a timeline per selection. Free, no key.
What you get
GET /history?fi=<match> returns the recorded price points for a match, oldest first. Each point has the time, the selection and its price, and whether it was suspended.
- All 24 sports, every market bet365 prices;
- pre-match and in-play in one timeline;
- recorded since September 2026: hundreds of millions of price points.
Pair it with closing lines for the last price before kickoff and /results for the final score.
Request
curl "https://moviodds.com/history?fi=201714836&sel=59223458"
| Parameter | Use |
|---|---|
fi | Match id (required). Pre-match and live ids both work and are merged. |
group | Only one market group, e.g. 40 for soccer Full Time Result. |
sel | Only one selection. |
from, to | Time window, RFC 3339 (2026-10-04T12:00:00Z) or Unix seconds. |
limit | Max rows, default 5000, up to 50000. truncated is true when you hit it. |
Sample response
A real timeline: the underdog's money line in LV Raiders v KC Chiefs (NFL, 4 October 2026), trimmed to its first and last points. It drifted from 2.80 to 2.90 before kickoff.
{
"fixture_id": "201714836",
"fixture_ids": ["201714836", "202267109"],
"count": 25,
"truncated": false,
"limit": 5000,
"points": [
{"ts": "2026-10-02T17:56:23Z", "fixture_id": "201714836", "group_id": "1441", "group_name": "Money Line", "sel_id": "59223458", "label": "KC Chiefs", "odds_dec": 2.8, "odds_frac": "9/5", "suspended": false},
…
{"ts": "2026-10-04T20:01:03Z", "fixture_id": "201714836", "group_id": "1441", "group_name": "Money Line", "sel_id": "59223458", "label": "KC Chiefs", "odds_dec": 2.9, "odds_frac": "19/10", "suspended": false},
{"ts": "2026-10-04T20:21:01Z", "fixture_id": "201714836", "group_id": "1441", "group_name": "Money Line", "sel_id": "59223458", "label": "KC Chiefs", "odds_dec": 2.9, "odds_frac": "19/10", "suspended": false}
]
}
Each point carries the same identity fields as /odds: group_name and label, plus side, line, handicap and n2 on the markets that use them (a totals leg, for example, carries "side": "O", "line": "2.5"). Fields are present only when they have a value.
Export to CSV
import csv, requests
h = requests.get("https://moviodds.com/history",
params={"fi": "201714836", "group": "1441"}, timeout=60).json()
with open("history.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["ts", "sel_id", "label", "odds_dec", "suspended"])
for p in h["points"]:
w.writerow([p["ts"], p["sel_id"], p.get("label", ""), p["odds_dec"], p["suspended"]])
print(h["count"], "rows")
Each point already names its market and selection (group_name, label, side, line), so you usually do not need a second call. If you want the full market list for a match, read its quotes from /odds: each quote has the same sel_id.
FAQ
Is the bet365 historical odds API free?
Yes. No sign-up and no key. /history allows 120 requests per minute per IP.
How far back does the history go?
To September 2026, when we started recording. Every price change since then is kept.
Does it include in-play odds?
Yes. Pre-match and in-play prices are in the same timeline, and points carry suspended when the market was closed.
Which sports and markets?
All 24 sports we cover and every market bet365 prices, from match winners to player props.
Are these really bet365 odds?
Yes, only bet365's own prices. MoviOdds is an independent project and is not affiliated with bet365.
More: closing lines · live WebSocket · all 24 sports · Python client · API docs