Leagues, seasons & standings#
Everything competition-level lives here. The one habit to build: resolve
the current season through the API (/leagues/{id}/season/) instead of
hardcoding season ids.
List leagues#
GET /api/v2/leagues/
| Param | Type | Description |
|---|---|---|
country |
string | Country name filter, e.g. Argentina |
is_women |
bool | Women's competitions only |
include_inactive |
bool | Also return leagues we no longer sync (hidden by default) |
limit / offset |
int | Pagination |
Any other parameter is a 400, not a silent no-op — the body names what you
sent and lists the ones we accept, so a typo (or a ?search= we do not
support) fails instead of handing back the unfiltered list. There is no name
search: filter by country and page the result.
curl -H "Authorization: Token YOUR_API_KEY" \
"https://sports.bzzoiro.com/api/v2/leagues/?country=Argentina"
League detail#
GET /api/v2/leagues/{id}/ # cached 5 min
Seasons#
GET /api/v2/leagues/{id}/seasons/ # all seasons, cached 60 min
GET /api/v2/leagues/{id}/season/ # current season only, cached 30 min
{ "id": 1635, "name": "Primera LPF 2026", "year": 2026,
"start_date": "2026-01-01", "end_date": "2026-12-31", "is_current": true,
"stages": [
{"stage": "regular-season", "stage_name": "Regular season",
"matches": 306, "rounds": 34,
"start_date": "2026-01-24", "end_date": "2026-12-06"}
] }
Season ids feed the season_id filter on
events, standings and leaderboards.
stages is the competition's structure in the order it is played — qualifying,
group or league phase, then knockouts — with the match and matchday counts of
each. It is the list of values the stage filter on
events accepts, so you never have to guess a slug.
See Competition structure.
Standings#
GET /api/v2/leagues/{id}/standings/?season_id=1635 # cached 10 min
Rows carry position, team_id, team name, played, won/drawn/lost, goals
for/against, points and recent form. Cup-style competitions return a
groups array (one table per group) instead of a single table — handle both.
Qualification & relegation zones#
Every row carries a zone describing what that position leads to, and the
response carries a zones legend so you can colour a table without walking
it. For a flat table zones is an array; for a grouped competition it is a
map keyed by group name, matching groups.
{
"standings": [
{ "position": 1, "team_name": "Sporting CP", "pts": 82,
"zone": { "key": "cl", "label": "Champions League", "type": "qualification" } },
{ "position": 9, "team_name": "Estoril", "pts": 41, "zone": null }
],
"zones": [
{ "key": "cl", "label": "Champions League", "type": "qualification", "from": 1, "to": 2 },
{ "key": "rel", "label": "Relegation", "type": "relegation", "from": 17, "to": 18 }
]
}
| Field | Description |
|---|---|
label |
The competition's own wording, verbatim — Champions League, Promotion Playoffs, Championship round, Copa Sudamericana |
type |
Coarse bucket: qualification · promotion · playoff · relegation · other. Colour and reason against this, not against the label |
key |
Stable short slug for the label (cl, elq, promo, rel, …). Useful as a CSS class |
from / to |
Legend only — the first and last position the band covers, 1-based and inclusive |
zone is null where the position leads nowhere in particular, and on the
handful of competitions that publish no zones at all and for which we have
declared none — some North American leagues, where qualification is decided
in a conference table rather than the overall one, and some women's
competitions. Treat a missing zone as "unknown", not as "no objective".
Zones describe the season total table. A team is labelled by the position it holds in the table you are reading, which for a few hours after a matchday can run ahead of the official one.
Whether a team has already secured or lost an objective mathematically is not part of this response.
Leaderboards#
GET /api/v2/leagues/{id}/top/{stat}/ # cached 10 min
| Param | Type | Description |
|---|---|---|
stat (path) |
string | scorers · assists · yellowcards · redcards · fouls |
season_id |
int | Defaults to the current season |
team_id |
int | Rank one squad instead of the whole league |
limit |
int | Default 20, max 50 |
Each row: rank, player_id, player_name, position, team_id,
team_name, value, matches. The response echoes team_id — null when you
did not filter.
One team's scorers. Use team_id rather than pulling the league table and
filtering it yourself. limit caps at 50, so a striker who is nowhere near his
league's top 50 is simply absent from that list, and an absence reads exactly
like a player who has not scored. With team_id the ranking is computed inside
the squad, so rank 1 is that club's leading scorer.
GET /api/v2/leagues/85/top/scorers/?team_id=1042&season_id=1635
Best XI#
GET /api/v2/leagues/{id}/bestxi/{season_id}/ # season best XI, cached 30 min
GET /api/v2/leagues/{id}/bestxi/{season_id}/{round_number}/ # matchday best XI, cached 10 min
Best-rated eleven in a formation layout — render straight onto a pitch graphic (combine with the Image API for faces).
Competition venues#
GET /api/v2/leagues/{id}/venues/?season_id=…
GET /api/v2/leagues/{id}/seasons/{season_id}/venues/
The second form is for tournament-style competitions and supports
host_country_code, hosts_final, hosts_opening, hosts_third_place and
round filters — built for World-Cup-style venue pages.
See also#
- Build a league page — these endpoints assembled into a working page
- Season objects are also queryable globally:
GET /api/seasons/?league=85and?current=trueon the v1 API