The identifier question comes first
The match service takes two required parameters, id and league, and both are positive numeric identifiers sent as strings. The id is not just any identifier attached to a match. It must be the match static_id returned by the score and statistics feeds. Score responses can carry more than one identifier for the same match, and an ordinary match id, a fixture id or an in-play id will not retrieve the record you want.
The league parameter is the competition identifier that corresponds to that match, as used by the commentary and statistics feeds. Take it from the same response where you found the static_id, rather than looking it up by name or carrying it over from a different system.
This is the most common integration problem we see with this service. A developer takes the first identifier-looking value in a score response, passes it as id, and receives nothing useful. Read a real response from your own account, find the static_id attribute for a match, and use that. Write it down in your mapping code with a comment, because the next person to touch the code will make the same mistake otherwise.
Why identifiers from different systems do not mix
Football data is assembled from several systems. Fixtures, live commentary and in-play services can each assign their own identifiers to the same real match. A number that identifies a match in one system means nothing in another, and occasionally the same number exists in two systems referring to different matches, which is worse than an outright failure because it can return the wrong game.
Keep each identifier in its own clearly named column. Never store them in a single generic id field. If you need to move between systems, the in-play mapping service on Growth and Pro exists to relate identifiers, and its output should be stored as an explicit mapping rather than assumed.
- Store static_id, ordinary match ids and in-play ids in separate columns.
- Take league from the same response as the static_id.
- Never guess an identifier by name or by numeric similarity.
Requesting one match
The example shows the shape of a call once you have both values. The placeholders are deliberate: use identifiers from your own score or statistics responses, not values copied from documentation, because a sample identifier from another day may no longer match anything useful.
The response uses the standard envelope, with data holding the source structure for the match and meta recording the feed, UTC fetch time, cache time of about a minute and qualification. We publish no normalised schema for this record, so map from a real sample and expect attributes to be present or absent depending on the competition.
STATIC_ID="from-a-score-response" # the static_id attribute, not id
LEAGUE_ID="from-the-same-response"
curl -sS -H "X-API-Key: $FOOTBALLAPI_KEY" \
"https://footballapi.net/api/v1/football/match?id=$STATIC_ID&league=$LEAGUE_ID" \
-o match.jsonCheck qualification before relying on it
Every published feed carries a qualification state, and for this operation we specifically advise checking it before you build a product feature that depends on it. At the time of review the feed is marked sample received: a response has returned through the gateway, while final freshness, coverage and licensing checks are pending. The meta object in each response repeats the qualification, so your code can read it at run time.
In practice, that means designing your match page so that the focused record enriches it rather than being the only source. If the match request fails or returns little, the page should still show the score and state from the score feed and statistics from the competition statistics feed. A 503 response with the feed_not_qualified code means the endpoint is not ready, and repeating the request will not activate it.
Designing a match page around one request
A good match page loads quickly and fills in progressively. Render the header first from data you already hold: teams, competition, kick-off and current score from your score snapshot. Then request the match record on your server and add its detail as it arrives. On match day, refresh the record about once a minute while the match is in progress, matching the cache time, and stop refreshing once it has finished and you have stored a final copy.
Caching matters here more than for league-wide feeds, because match pages are visited individually. If a popular match has thousands of readers, they should all read your one cached copy, refreshed once a minute, rather than each triggering a request.
One match or a whole competition?
The competition match statistics feed returns statistics for many matches in a competition with a single leagueId request. If you are building pages for every match in a round, that feed is far cheaper: one request serves ten match pages. The match service is the right tool when you need a single game, perhaps from a different competition, or when its focused record carries detail your product needs that the competition feed does not.
Many products use both: the competition feed for broad coverage on match days and the match service for featured games. Keep their mappings separate and record which source produced each value on your page.
Testing identifier handling
Save a score response, extract the static_id and league from it in tests, and assert your request builder uses those values. A second test should confirm that an ordinary match identifier is rejected by your own validation before any request is sent. These two tests prevent the most common integration mistake with this service.
Caching match records
Cache each match record by static_id and league. Refresh finished matches occasionally for corrections, not on every page view.
Reading errors
A 400 invalid_parameter response usually means a missing league value or a malformed identifier. A 404 suggests the static_id and league do not identify a match the source holds. A 403 means the service is not included or not activated. Keep the requestId from each error body for support.
Plan scope
The match service is not included in Starter. It requires Growth at EUR 99 a month or Pro at EUR 249, plus separate activation of the service for your account. A Starter key calling it receives a 403 response with the subscription_required code, and that refusal is not billed.
On Growth, a featured-match page refreshed once a minute for two hours uses about 120 requests, well within the daily inclusion of 25,000 successful requests. Pro raises the inclusion to 250,000. Above the inclusion, each successful request is EUR 0.002 on the monthly EUR invoice. No free trial is offered, and no VAT is currently charged.
Not a tracking feed
A detailed match record can describe what happened in a game, as recorded by the source. It is not a positional feed and contains no ball or player coordinates. Requesting it does not activate the separate ball tracker area of the site or any streaming service. If your product needs positional data, raise it with support before planning around this service.
Questions developers ask
- Which identifier goes in the id parameter?
- The match static_id from a score or statistics response. Ordinary match ids, fixture ids and in-play ids are not interchangeable with it.
- Where do I get the league value?
- From the same score or statistics response as the static_id. It is the competition identifier for that match.
- Is the match service on Starter?
- No. It requires Growth or Pro and separate service activation.
- Should I use this for every match in a round?
- Usually not. The competition match statistics feed serves many matches in one request. Use the match service for individual or featured games.
- Does the match record include ball tracking?
- No. It contains no positional data and does not activate the ball tracker.
- What does a 503 feed_not_qualified response mean?
- The endpoint is not ready for your account. Repeating the request will not activate it.
Guides and documentation
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.