Growing Discord community — direct access to the developer, live coverage & picks. Join the Discord Join now →
Matches Leagues Predictions The Edge Money News Stats Coverage
Docs / Football API free

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=85 and ?current=true on the v1 API
View this page as Markdown · Found a mistake? Tell us