Skip to content
Fixtures and competitions

Football competitions API for discovering league identifiers

Almost every league-scoped request needs a leagueId, and the competitions directory is where those identifiers come from. This page explains how to use the directory as a lookup table, why a listed competition is not a coverage promise, and why the directory sits outside the Starter plan.

Primary endpoint

GET/api/v1/football/competitions

No query parameters.

Access: Growth and Pro. Header: X-API-Key.

Illustration of a card index with tabs, each tab holding a small football pennant.
The competitions directory is a card index of identifiers, not a guarantee that every feed covers every card.
01

The lookup table behind every league request

Fixtures, standings, squads, match statistics, predicted line-ups and the three leaderboard feeds all take a required leagueId. That value is not a name and not a code you can guess. It is a positive numeric identifier from the source system, sent as a string, and the competitions directory is the published place to discover it. Think of this feed as the index at the back of a book: you do not read it for its own sake, you read it to find the page you need.

The directory takes no parameters. A single request returns the competitions the source lists for the package, wrapped in the standard gateway envelope. The data object carries the source structure as supplied, and meta tells you which feed answered, when it was fetched in UTC and how long it is cached. We have not imposed our own schema on the directory, so the attribute that holds a competition's identifier, its display name and any country or grouping details should be read from a real response rather than assumed from this page.

One distinction is worth stating early. Competition identifiers are not match identifiers, fixture identifiers or in-play identifiers. They live in different systems and are not interchangeable. Passing a match identifier as a leagueId will not work, and a numeric coincidence between two systems means nothing.

02

Listed is not the same as covered

A competition appearing in the directory tells you the source knows about it. It does not tell you that every feed has data for it, that every season is populated, or that statistics, line-ups or leaderboards exist at the same depth as for a top division. A lower-tier league might return a full fixture list and a table but very little in the statistics feed. A cup might have fixtures and results but no leaderboard.

The practical consequence is that your onboarding of a new competition should include a short probe. Request the fixtures and standings for its leagueId, look at what comes back, and only then add the competition to your product. That probe costs a handful of requests and saves you from launching a league page that turns out to be mostly empty.

  • Probe fixtures and standings for a new leagueId before launching a page.
  • Record, per competition, which feeds returned useful data for you.
  • Check the seasons directory before promising any archive range.
From directory to league-scoped feedsFlow: request the competitions directory, store competition IDs as strings, choose the competitions your product needs, and pass each ID as leagueId to fixtures, standings, squads and leaderboards.01competitionsdirectory call02Store IDsas strings03Choose leaguesyour product04leagueId=other feeds
From directory to league-scoped feeds. Read the directory once in a while, keep IDs as strings, then use them as leagueId elsewhere.
03

Keeping a local copy of the directory

The catalogue cache time for this feed is an hour, and competitions change rarely. Fetching it once a day, or even once a week, is plenty. Store the raw response with its fetch time, then build whatever lookup your product needs from that stored copy. The Python example writes the envelope to disk unchanged so you can diff successive copies and spot new or removed entries.

If a competition you rely on disappears from a later copy, do not delete it from your product automatically. Flag it, check whether the league-scoped feeds still answer for its leagueId, and decide deliberately.

Python: save a dated copy of the directorypython
import os, json, datetime, requests

r = requests.get(
    "https://footballapi.net/api/v1/football/competitions",
    headers={"X-API-Key": os.environ["FOOTBALLAPI_KEY"]},
    timeout=30,
)
body = r.json()
if not r.ok:
    raise SystemExit(f"{r.status_code} {body.get('code')} {body.get('requestId')}")
day = datetime.date.today().isoformat()
with open(f"competitions-{day}.json", "w") as f:
    json.dump(body, f)  # data and meta kept as returned
05

Testing the directory

Save a directory response and test that your code keeps identifiers as strings, handles competitions you do not cover and does not delete a stored competition because it is missing from one response. These tests are short and prevent the most expensive class of directory bug: a league silently vanishing from your product.

06

Labels and naming

Show competition names as supplied and add your own country context only where the supplied data supports it.

07

Why this directory is a Growth and Pro service

The competitions directory is a global service. It is not included in Starter, and on Growth and Pro it requires the service to be activated for your account. The reason is structural. Starter is built around five leagues you select from a verified list in the dashboard, and league-scoped responses are filtered to those five. A global directory of every competition sits outside that model, so Starter customers find their league identifiers through the dashboard selection list instead.

Growth at EUR 99 a month and Pro at EUR 249 include all available package leagues, and those plans are where a directory-driven product makes sense: a site that lets readers browse any competition, or a tool that onboards leagues on demand. Requests above the daily inclusion of 25,000 or 250,000 successful requests are EUR 0.002 each on the monthly EUR invoice, and failed or denied calls are not billed. A 403 response with the subscription_required code means the key is valid but the account is not entitled to this feed yet.

08

Handling renames and new entries

Competitions are renamed more often than people expect, usually for sponsorship and sometimes after a governance change. Because your product stores the identifier rather than the name, a rename is a display update rather than a migration. Compare each new directory copy with the last one by identifier, and when a name changes, update the label and keep the old one in a history field so search still finds pages that readers remember by the earlier name. New entries deserve a short review before anyone builds on them. Check which feeds answer for the new identifier, which seasons exist, and whether it duplicates something you already cover under a different label.

09

Where to go after the directory

With an identifier in hand, the usual next steps are the season fixtures for a schedule, standings for the table, squads for the registered players, and the scorers, assists and cards leaderboards. For past data, take the seasons directory next: historical fixtures and standings need a season value as well as the leagueId, and the seasons feed is where valid values are listed.

The directory is also where a careful integration notices change. A new competition appearing at the start of a season, or a competition whose name has changed, is visible here first. Treat each weekly copy as an opportunity to review rather than as something to import blindly.

Questions developers ask

Does the competitions feed take any parameters?
No. One request returns the directory; filter and search it from your own stored copy.
Is the competitions directory included in Starter?
No. It requires Growth or Pro and separate service activation. Starter customers choose leagues from the dashboard selection list.
Can I use a match ID as a leagueId?
No. Competition, match, fixture and in-play identifiers come from different systems and are not interchangeable.
Does a listed competition have full statistics?
Not necessarily. A listing does not guarantee that every feed or season is covered. Probe the feeds you need for each new leagueId.
How often should I refresh the directory?
Daily or weekly is plenty. The feed is cached for about an hour and competitions change rarely.

Check the plan before you write the integration.

Starter EUR 29, Growth EUR 99, Pro EUR 249 per month. No free trial. No VAT currently charged.