The identifier is the club
The team service takes one required parameter, teamId, a positive numeric team identifier sent as a string. Take it from a fixture, score, squad or standings response rather than from a name search. In football data, the identifier is the club: names change with sponsorship and history, short names differ between competitions, and two clubs in different countries can share a name. The identifier stays put.
Build your club pages around that identifier. Use it in your database as the key and, if you like, in your URLs alongside a readable slug. When a club is renamed, the page keeps its identity and the slug can be updated with a redirect.
Profiles of uneven depth
Responses use the standard gateway envelope. The data object holds the profile as the source supplies it; meta records the feed, UTC fetch time, cache time of about an hour and qualification. We have not published a normalised team profile schema. Identifiers are strings and source attributes keep their at-sign prefix.
Profile depth varies widely. A major club may have a rich record with founding details, venue information and more; a small club in a lower division may have little beyond a name. Treat every attribute as optional. A club page template that assumes a stadium capacity or founding year will either crash or display placeholder values for the many clubs where those are not supplied. Show what exists and leave out what does not.
- Treat every profile attribute as optional.
- Hide empty sections instead of showing placeholders.
- Never fill a missing founding year or capacity with an estimate.
Fetching a profile on demand
Team profiles change slowly, so request each on demand when a page is first built and cache it for a day or more. The example shows a simple read-through cache. Replace the placeholder with an identifier from your own fixtures or squads; documentation examples do not refer to any particular club.
export async function teamProfile(teamId: string) {
const hit = await cache.get(`team:${teamId}`);
if (hit) return hit;
const q = new URLSearchParams({ teamId }); // e.g. a string ID from your squads
const res = await fetch(`https://footballapi.net/api/v1/football/team?${q}`, {
headers: { "X-API-Key": process.env.FOOTBALLAPI_KEY! },
});
const body = await res.json();
if (res.ok) await cache.set(`team:${teamId}`, body, { ttlHours: 24 });
return body;
}Assembling a full club page
A profile on its own is a thin page. The value comes from joining it to other services by the same identifier: the crest from the team image service, the roster from squads, upcoming matches from fixtures or upcoming, the club's position from standings, and on Growth and Pro, head-to-head records for the next opponent. Each join uses the string team identifier, never the name.
Render the page on the server so it is fast and readable without scripts, and include the date each component was last refreshed. Club pages are high-traffic during transfer windows and on match days; serve them from your cache rather than calling the API per visit.
Keeping profiles fresh without re-requesting everything
A site with hundreds of clubs could refresh every profile every day, but most of those requests would return unchanged data. The updated-teams service on Growth and Pro lists team identifiers the source has recently updated. Use it as a hint: refresh the profiles it lists, and run a slower full sweep, weekly or monthly, to catch anything the hint missed.
That combination keeps profiles reasonably current at a fraction of the request cost. Treat the update list as a helpful signal rather than a complete change log; it does not guarantee that every change appears.
Names, short names and translations
Clubs have several names in practice: an official name, a common name, a short name for scoreboards and sometimes translated names. The profile carries whatever names the source supplies. For narrow displays such as score tiles, the team abbreviations service on Growth and Pro supplies short codes.
Do not invent your own abbreviations or translations and present them as data. If your editors maintain preferred display names, store them in a separate editorial field keyed by team identifier, and fall back to the supplied name when no editorial override exists.
Venue information with care
Where the source supplies venue details in a profile, they are among the most useful fields for readers planning to attend a match. They are also among the most likely to be out of date: clubs move grounds, share stadiums temporarily during redevelopment and play some matches elsewhere. Show supplied venue details with the date you last refreshed them, and for match-specific information such as where a particular fixture is played, prefer details from the fixture itself if the source supplies them there.
Do not compose directions, transport advice or capacity claims from profile data. Link to the club's own information for anything a visitor will rely on.
Clubs with several teams
Many clubs field more than one team in the data: a first team, a reserve or under-23 side, a women's team. The source may give each its own team identifier and profile. Treat them as distinct teams in your data model, joined to a shared club concept in your own editorial layer if your product needs one. Do not merge them by name, because their squads, fixtures and tables are entirely separate, and a reader looking for the women's team will be poorly served by a page that mixes in men's fixtures.
Static club pages and search
Club pages attract steady search traffic. Pre-render them on the server with the supplied name in the title and heading, the competition the club currently plays in and links to its fixtures, squad and table. Refresh them when the update hint lists the team or on your periodic sweep. Pages that load quickly and present real, current information do better for readers than thin pages assembled in the browser after several requests.
Handling profile errors
A 404 for a team profile usually means the identifier is wrong or the source holds no profile for that team. Check where the identifier came from before assuming a problem with the service. A 403 means the account is not entitled, typically a Starter key. A 503 with the feed_not_qualified code means the service is not ready for your account, and retrying will not change that. Log the requestId from every error body so support can trace specific calls.
Testing with sparse profiles
Save a rich profile and a sparse one and render both in tests. Sparse profiles are where layouts break: empty headings, dangling labels, stray separators. Your page should look deliberate when only a name is supplied.
Plan scope
Team profiles are a global service and are not included in Starter. The service requires Growth at EUR 99 a month or Pro at EUR 249, plus activation for your account. Starter keys receive a 403 response with the subscription_required code, which is not billed.
With a day-long cache and update hints, a site with two hundred clubs might use a few dozen profile requests on an ordinary day. Above the daily inclusion of 25,000 on Growth or 250,000 on Pro, each successful request is EUR 0.002 on the monthly EUR invoice. No free trial is offered, and no VAT is currently charged.
Questions developers ask
- What parameter does the team service require?
- teamId, a positive numeric team identifier sent as a string.
- Where do I get a teamId?
- From fixture, score, squad or standings responses. Avoid looking teams up by name.
- Why are some profiles nearly empty?
- Profile depth depends on what the source records. Treat all fields as optional and hide missing sections.
- Are team profiles on Starter?
- No. Team profiles require Growth or Pro and separate service activation.
- How do I know when to refresh a profile?
- Use the updated-teams feed as a hint, plus an occasional full sweep. It is not a complete change log.
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.