The two-step workflow
Every season-scoped Football V2 endpoint takes a numericseasonId — never a year string. Human-readable labels like "24/25" or "2024" are display names returned in the name and year fields. They are not valid URL parameters.
Resolve the ID first, then use it everywhere else:
Why the label format varies
Different leagues run on different calendars, so the upstreamname field reflects the real-world season:
The
id field is always numeric and always the right value to pass downstream. The format of name only matters when you want to display the season to a human user.
Worked example: split-year league (Premier League)
uniqueTournament.id = 17
Worked example: calendar-year league (MLS)
uniqueTournament.id = 242
The flow is identical — only the season name differs:
Recipe: fetch a full season of historical matches
Combine seasons → rounds → events to walk an entire competition:tournamentId and the resulting seasonId change.
Caching the resolution step
/seasons is a low-volatility endpoint — the active season changes at most a few times per year. Cache the response client-side (24h TTL is safe) so you only pay the discovery cost once per league per day.
Related
- Canonical IDs —
uniqueTournament.id(store this) vstournament.id(per-season variant) - Tournament Endpoints — full list of season-scoped routes
- Troubleshooting — common 404 patterns