Introduction
What Soccer Data covers, and the conventions every endpoint shares.
Soccer Data is a read-only REST API for football. You send GET requests over HTTPS with your API key, and every answer is JSON. This page covers what's inside and the few rules that apply everywhere.
What you can get
| Area | What's included |
|---|---|
| Competitions | Leagues, cups and international tournaments, with their seasons, groups and league tables. |
| Teams | Profiles, squads, season records, standings history, injuries and suspensions. |
| Players | Profiles, season totals, injuries and suspensions, season heatmaps. |
| Matches | Fixtures, results, live scores, lineups, event timelines, team and player stats, referees. |
| xG | Shot maps with an xG value for every shot, plus per-match player heatmaps. |
| Odds | Pre-match and in-play prices from Bet365, Paddy Power, BetMGM UK, Pinnacle and Betfair Exchange, where they exist. |
| Coverage | Which competitions and seasons have which kinds of data. |
Not every competition has every kind of data, and how far back the history goes depends on the competition. Competitions and matches carry flags such as xg_available and odds_available so you can check before you ask. The Coverage page explains how to see exactly what exists.
Base URL
Every path in these docs sits under this base URL:
https://api.soccer-data.co/v1
Authentication
Put your API key in the X-Api-Key header of each request. Keys belong on your server, never in code that runs in a browser or an app you ship to users. See Authentication for the details.
curl "https://api.soccer-data.co/v1/competitions/competition_705uv6jm8myn" \
-H "X-Api-Key: YOUR_API_KEY"
Requests
All endpoints use GET. Filters go in the query string:
curl "https://api.soccer-data.co/v1/matches?team_id=team_f0ibhxdw7hs5&status=finished" \
-H "X-Api-Key: YOUR_API_KEY"
If you send a parameter an endpoint doesn't know, including a typo, you get a 400 with the code UNKNOWN_PARAMETER. The message suggests the closest valid parameter, when one is close, and lists the ones the endpoint accepts, so mistakes are quick to fix.
IDs
Each thing in the API has an id that starts with a word saying what it is, such as competition_, season_, team_, player_ or match_, followed by 12 letters and digits. For example, the Premier League is competition_705uv6jm8myn and Arsenal is team_f0ibhxdw7hs5.
Ids never change, so you can store them in your own database. Treat them as plain strings and use them exactly as you received them. Data model lists every kind, and Find any ID shows how to look them up.
Dates and times
- Date filters such as
date_fromanddate_totakeYYYY-MM-DD. There is no singledateparameter; to get one day, set both to the same date. - Kickoff times in responses are in UTC, in ISO 8601 format (for example
2026-10-10T11:30:00.000Z). Convert them to local time in your app.
Responses
List endpoints return a data array plus a meta object for paging:
{
"data": [
{
"id": "team_f0ibhxdw7hs5",
"name": "Arsenal",
"short_name": "Arsenal",
"country": "England",
"is_mens_team": true,
"primary_competition": { "id": "competition_705uv6jm8myn", "name": "Premier League" }
}
],
"meta": { "page": 1, "per_page": 1, "total": 13, "total_pages": 13 }
}
Endpoints that return a single thing put one object in data:
{
"data": {
"id": "competition_705uv6jm8myn",
"name": "Premier League",
"country": "England",
"type": "league",
"xg_available": true,
"current_season_id": "season_hr1ie7yrsdmt",
"total_teams": 20
}
}
Pagination explains meta and how to walk through every page.
Errors
Every error has the same shape, so one handler covers them all:
{
"error": {
"code": "NOT_FOUND",
"message": "Match not found",
"status_code": 404
}
}
Write your logic against code, which is stable, rather than the message. Errors lists every code and what to do about it.
Limits and freshness
Each plan has a per-minute limit and a daily limit, and every response tells you how much you have left in its headers. Answers that change during a match are cached briefly: normally for 15 seconds on paid plans and 5 minutes on Free. If a fresh answer can't be fetched, you may get an older copy marked X-Cache: STALE. Rate limits has the numbers.
Getting new data
The API works by pulling: there are no webhooks or streaming connections. To follow a live match, call the live endpoints at a steady pace. Live matches shows how to do that without wasting requests.
Changes over time
We add endpoints, parameters and response fields as the API grows. Write your client so it ignores fields it doesn't recognise, and it won't break when something new appears.
Next steps
- Quickstart: make your first requests.
- Build with AI: let an AI coding tool write the integration.
- Authentication: set up your key properly.
# Introduction
What Soccer Data covers, and the conventions every endpoint shares.
Soccer Data is a read-only REST API for football. You send `GET` requests over HTTPS with your API key, and every answer is JSON. This page covers what's inside and the few rules that apply everywhere.
## What you can get
| Area | What's included |
|---|---|
| Competitions | Leagues, cups and international tournaments, with their seasons, groups and league tables. |
| Teams | Profiles, squads, season records, standings history, injuries and suspensions. |
| Players | Profiles, season totals, injuries and suspensions, season heatmaps. |
| Matches | Fixtures, results, live scores, lineups, event timelines, team and player stats, referees. |
| xG | Shot maps with an xG value for every shot, plus per-match player heatmaps. |
| Odds | Pre-match and in-play prices from Bet365, Paddy Power, BetMGM UK, Pinnacle and Betfair Exchange, where they exist. |
| Coverage | Which competitions and seasons have which kinds of data. |
Not every competition has every kind of data, and how far back the history goes depends on the competition. Competitions and matches carry flags such as `xg_available` and `odds_available` so you can check before you ask. The [Coverage](/docs/concepts/coverage) page explains how to see exactly what exists.
## Base URL
Every path in these docs sits under this base URL:
```text
https://api.soccer-data.co/v1
```
## Authentication
Put your API key in the `X-Api-Key` header of each request. Keys belong on your server, never in code that runs in a browser or an app you ship to users. See [Authentication](/docs/authentication) for the details.
```bash
curl "https://api.soccer-data.co/v1/competitions/competition_705uv6jm8myn" \
-H "X-Api-Key: YOUR_API_KEY"
```
## Requests
All endpoints use `GET`. Filters go in the query string:
```bash
curl "https://api.soccer-data.co/v1/matches?team_id=team_f0ibhxdw7hs5&status=finished" \
-H "X-Api-Key: YOUR_API_KEY"
```
If you send a parameter an endpoint doesn't know, including a typo, you get a `400` with the code `UNKNOWN_PARAMETER`. The message suggests the closest valid parameter, when one is close, and lists the ones the endpoint accepts, so mistakes are quick to fix.
## IDs
Each thing in the API has an id that starts with a word saying what it is, such as `competition_`, `season_`, `team_`, `player_` or `match_`, followed by 12 letters and digits. For example, the Premier League is `competition_705uv6jm8myn` and Arsenal is `team_f0ibhxdw7hs5`.
Ids never change, so you can store them in your own database. Treat them as plain strings and use them exactly as you received them. [Data model](/docs/concepts/data-model) lists every kind, and [Find any ID](/docs/guides/finding-ids) shows how to look them up.
## Dates and times
- Date filters such as `date_from` and `date_to` take `YYYY-MM-DD`. There is no single `date` parameter; to get one day, set both to the same date.
- Kickoff times in responses are in UTC, in ISO 8601 format (for example `2026-10-10T11:30:00.000Z`). Convert them to local time in your app.
## Responses
List endpoints return a `data` array plus a `meta` object for paging:
```json
{
"data": [
{
"id": "team_f0ibhxdw7hs5",
"name": "Arsenal",
"short_name": "Arsenal",
"country": "England",
"is_mens_team": true,
"primary_competition": { "id": "competition_705uv6jm8myn", "name": "Premier League" }
}
],
"meta": { "page": 1, "per_page": 1, "total": 13, "total_pages": 13 }
}
```
Endpoints that return a single thing put one object in `data`:
```json
{
"data": {
"id": "competition_705uv6jm8myn",
"name": "Premier League",
"country": "England",
"type": "league",
"xg_available": true,
"current_season_id": "season_hr1ie7yrsdmt",
"total_teams": 20
}
}
```
[Pagination](/docs/concepts/pagination) explains `meta` and how to walk through every page.
## Errors
Every error has the same shape, so one handler covers them all:
```json
{
"error": {
"code": "NOT_FOUND",
"message": "Match not found",
"status_code": 404
}
}
```
Write your logic against `code`, which is stable, rather than the message. [Errors](/docs/concepts/errors) lists every code and what to do about it.
## Limits and freshness
Each plan has a per-minute limit and a daily limit, and every response tells you how much you have left in its headers. Answers that change during a match are cached briefly: normally for 15 seconds on paid plans and 5 minutes on Free. If a fresh answer can't be fetched, you may get an older copy marked `X-Cache: STALE`. [Rate limits](/docs/concepts/rate-limits) has the numbers.
## Getting new data
The API works by pulling: there are no webhooks or streaming connections. To follow a live match, call the live endpoints at a steady pace. [Live matches](/docs/guides/live-matches) shows how to do that without wasting requests.
## Changes over time
We add endpoints, parameters and response fields as the API grows. Write your client so it ignores fields it doesn't recognise, and it won't break when something new appears.
## Next steps
- [Quickstart](/docs/quickstart): make your first requests.
- [Build with AI](/docs/build-with-ai): let an AI coding tool write the integration.
- [Authentication](/docs/authentication): set up your key properly.