Darts API#
The Darts API covers professional darts: players with ELO ratings, tournaments, matches with set and leg scores, official rankings and ELO-based win predictions.
Base URL: https://sports.bzzoiro.com/darts/api/v2/
Access#
Requires the Sports Addon ($5/month) — it unlocks the tennis, CS2, darts, hockey, basketball and horse racing APIs plus their MCP servers. Get it at /addons/. You also need a free account token from /register/.
Authorization: Token YOUR_API_KEY
Without a token you get 401:
{"error": "authentication required", "code": "authentication_required",
"detail": "Send Authorization: Token <YOUR_TOKEN> on every request.",
"register": "https://sports.bzzoiro.com/register/"}
With a token but no addon you get 402:
{"error": "Sports Addon required", "code": "addon_required",
"detail": "Tennis, CS:GO, darts, hockey, basketball and horse racing APIs require the Sports Addon ($5/mo).",
"pricing_url": "https://sports.bzzoiro.com/pricing/"}
List endpoints paginate with limit (default 50, max 200) and offset, and
return {count, next, previous, results}.
Endpoints#
| Endpoint | Description |
|---|---|
GET /darts/api/v2/players/ |
List/search players with ELO |
GET /darts/api/v2/players/{id}/ |
Player detail |
GET /darts/api/v2/tournaments/ |
List tournaments |
GET /darts/api/v2/tournaments/{id}/ |
Tournament detail |
GET /darts/api/v2/matches/ |
List matches |
GET /darts/api/v2/matches/live/ |
Matches in play right now |
GET /darts/api/v2/matches/{id}/ |
Match detail with legs and current set |
GET /darts/api/v2/matches/{id}/odds/ |
Per-bookmaker odds, every market |
GET /darts/api/v2/matches/{id}/h2h/ |
Head-to-head between the two players |
GET /darts/api/v2/predictions/ |
ELO-based win probabilities |
GET /darts/api/v2/predictions/{id}/ |
One prediction |
GET /darts/api/v2/rankings/ |
Official rankings (PDC by default) |
The machine-readable schema is public at /darts/api/schema/, with an
interactive UI at /darts/api/docs/ and a themed explorer
at /docs/explorer/darts/.
Players#
Query parameters
| Param | Type | Description |
|---|---|---|
search |
string | Name search |
country |
string | ISO country code |
limit / offset |
int | Pagination (default 50, max 200) |
Responses are cached ~5 minutes.
curl -H "Authorization: Token YOUR_API_KEY" \
"https://sports.bzzoiro.com/darts/api/v2/players/?search=littler"
{"count": 1, "results": [
{"id": 507, "name": "Luke Littler", "country_code": "GB", "elo": 1892}
]}
Tournaments#
Query parameters
| Param | Type | Description |
|---|---|---|
category |
string | Tournament category (e.g. Premier League, World Championship) |
include_inactive |
bool | Include past/inactive tournaments |
limit / offset |
int | Pagination |
{"count": 8, "results": [
{"id": 44, "name": "World Matchplay 2026", "category": "PDC Major"}
]}
Matches#
Query parameters
| Param | Type | Description |
|---|---|---|
tournament |
int | Filter by tournament id |
player |
int | Matches involving this player id |
status |
string | scheduled, live, finished, walkover, postponed, cancelled |
date_from / date_to |
date | YYYY-MM-DD. Without either, the list returns the next 7 days, oldest first. Any of the filters above lifts that window and returns the full archive, newest first. |
limit / offset |
int | Pagination |
curl -H "Authorization: Token YOUR_API_KEY" \
"https://sports.bzzoiro.com/darts/api/v2/matches/?player=507&status=finished"
{"count": 11, "results": [
{"id": 20841, "tournament": {"id": 44, "name": "World Matchplay 2026"},
"player1": {"id": 507, "name": "Luke Littler", "country_code": "GB"},
"player2": {"id": 312, "name": "Luke Humphries", "country_code": "GB"},
"match_date": "2026-07-27T20:00:00+00:00", "status": "finished",
"round_name": "Final", "player1_sets": 6, "player2_sets": 4,
"sets_detail": "3-1, 1-3, 3-2, 3-0, 1-3, 2-3, 3-1, 3-2, 2-3, 3-1",
"winner_id": 507, "best_of_legs": 5, "best_of_sets": 11,
"first_to_throw_id": 507}
]}
best_of_legs / best_of_sets and first_to_throw_id are null when the
match format wasn't reported upstream.
GET /matches/live/ returns in-play matches only. GET /matches/{id}/ adds
player1_legs, player2_legs and current_set for live scoreboards:
{"id": 20855, "status": "live", "player1_sets": 2, "player2_sets": 1,
"player1_legs": 2, "player2_legs": 1, "current_set": 4}
Odds#
GET /darts/api/v2/matches/{id}/odds/ returns every price we hold for one match: the
match-winner market flattened per bookmaker, and below it every other market the
books offered, grouped by kind, line and period.
curl -H "Authorization: Token YOUR_API_KEY" \
"https://sports.bzzoiro.com/darts/api/v2/matches/4664/odds/"
{"match_id": 4664, "match_date": "2026-08-14T19:00:00+00:00",
"player1_name": "Luke Humphries", "player2_name": "Michael van Gerwen",
"bookmakers_count": 47, "source": "multi",
"bookmakers": [
{"bookmaker": "Bet365", "bookmaker_slug": "bet365",
"odds_player1": 1.25, "movement_player1": "SHORTENING",
"odds_player2": 3.75, "movement_player2": "DRIFTING",
"updated_at": "2026-08-14T07:55:44Z"}
],
"markets": [
{"market_kind": "WINNER", "market_family": "WINNER", "market_line": null,
"market_period": "FT", "selections": ["P1", "P2"],
"bookmakers": [
{"bookmaker": "Bet365", "bookmaker_slug": "bet365",
"prices": {"P1": {"price": 1.25, "movement": "SHORTENING"},
"P2": {"price": 3.75, "movement": "DRIFTING"}},
"updated_at": "2026-08-14T07:55:44Z"}
]}
]}
| Field | Meaning |
|---|---|
source |
multi per-bookmaker prices, consensus the single stored price when the match is not yet linked to a priced feed event, none when nobody has priced it |
bookmakers_count |
Bookmakers with at least one match-winner price |
movement_* |
SHORTENING, DRIFTING or STABLE against the previous price we saw; null when there is no previous price |
market_kind |
Market type: WINNER, OU (total legs or 180s) |
market_family |
Distinguishes markets sharing a kind (total goals vs corners vs a single side's total) |
market_line |
The handicap or total the market is quoted on; null for a plain winner market |
market_period |
FT for the full match; period codes otherwise |
Prices come from several sources and are pooled per match. A bookmaker appears once per market with its most recent price.
Predictions#
Win probabilities derived from player ELO ratings.
Query parameters
| Param | Type | Description |
|---|---|---|
upcoming |
bool | Only matches not yet started |
limit / offset |
int | Pagination |
{"count": 5, "results": [
{"id": 3308, "match_id": 20860,
"player1_win_prob": 0.67, "player2_win_prob": 0.33,
"predicted_winner_id": 507}
]}
Rankings#
Query parameters
| Param | Type | Description |
|---|---|---|
type |
string | Ranking list, default PDC (also ProTour) |
date |
date | Snapshot date (YYYY-MM-DD); default latest |
limit / offset |
int | Pagination |
Cached 5 minutes.
{"count": 128, "results": [
{"id": 71002, "position": 1, "type": "PDC", "prize_money": 1710000,
"player": {"id": 312, "name": "Luke Humphries", "country_code": "GB"}}
]}
Head-to-head#
GET /matches/{id}/h2h/ returns every finished meeting between the two players,
whichever side of the board they were on, with their three-dart averages across
those matches. It is computed from the archive, so there is nothing to sync and
nothing to go stale.
curl -H "Authorization: Token YOUR_API_KEY" \
"https://sports.bzzoiro.com/darts/api/v2/matches/4410/h2h/"
{"match_id": 4410,
"player1": {"id": 1, "name": "Luke Littler"},
"player2": {"id": 2, "name": "Luke Humphries"},
"total_matches": 23, "player1_wins": 15, "player2_wins": 8,
"player1_avg": 101.37, "player2_avg": 100.94,
"recent_matches": [
{"id": 4292, "date": "2026-06-06T19:53:00+00:00",
"tournament": {"id": 150, "name": "Nordic Darts Masters 2026"},
"round_name": "Semifinals", "winner": "player2",
"player1_sets": 5, "player2_sets": 7}
]}
player1 and player2 always mean the two players of the match you asked
about; meetings stored the other way round are flipped for you.
Coverage and off-season#
The darts calendar is a run of separate tournaments rather than a continuous season, so quiet weeks are normal and the match list is empty during them.
GET /api/v2/coverage/?sport=darts says so directly, without a token:
{"sport": "darts", "status": "no_fixtures", "events_next_7d": 0,
"events_next_30d": 0, "priced_next_7d": 0, "live_now": 0,
"next_event_at": null, "last_event_at": "2026-08-15T10:23:00+00:00"}
status is in_season (fixtures within seven days), between_events (nothing
this week, something later), off_season (nothing ahead and the last event is
more than a fortnight old) or no_fixtures. Drop the ?sport= to get every
sport in one call — worth doing before a polling loop decides what to ask for.