# Basketball API complete reference

Basketball data through one REST API: competitions, seasons, teams, games, box scores, play by play, shots, players and game logs.

- Base URL: `https://api.basketballapi.net/v1`
- Authentication: `Authorization: Bearer <key>` or `X-API-Key: <key>`
- Site: https://basketballapi.net
- Endpoints: 21
- Generated: 2026-10-10 00:06 UTC (the newest change to its sources)
- This file: https://basketballapi.net/documentation/manual.md

## Before anything else

- Factual data only: scores, statistics and events. No predictions, ratings, tips or betting advice on any endpoint.
- Every answer is `{"data", "meta"}`. `meta` carries paging (`count`, `next_cursor`, `page`, `per_page`, `total`, `total_pages`) on lists, and the plan that answered.
- Every error is `{"error": {"code", "message", "docs"}}`.
- Ids are strings with a prefix: `cp_` competition, `ss_` season, `tm_` team, `gm_` game, `pl_` player.

## Plans

| Plan | Price a month | Calls a day | Calls a minute |
| --- | --- | --- | --- |
| Free key | Free | 100 | 10 |
| Live | $29 | 10,000 | 60 |
| Archive | $79 | 50,000 | 60 |
| Complete | $199 | 250,000 | 120 |

Plans and prices: https://basketballapi.net/pricing

## Endpoints

### Games

Games, results, box scores, play by play, shots and closing prices.

#### `GET /v1/games`

Games: Games by day, dates, competition, season, team or status.

Plans: Free key and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `date` | query | date | no | One day, as YYYY-MM-DD. |
| `from` | query | date | no | The first day, as YYYY-MM-DD. |
| `to` | query | date | no | The last day, as YYYY-MM-DD. |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `team` | query | id | no | Only this team, by its id (tm_…). |
| `status` | query | enum | no | One of: scheduled, final, no_result. |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "gm_C513E9BF",
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "season": {
                "id": "ss_EBC81C6D",
                "name": "Example name"
            },
            "stage": "regular",
            "round": "12",
            "date": "2026-10-01",
            "tip_off": "2026-10-01T19:45:00Z",
            "status": "scheduled",
            "home": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "away": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "home_score": 88,
            "away_score": 81,
            "attendance": 11204,
            "venue": "text",
            "has": {
                "boxscore": true,
                "playbyplay": true,
                "shots": true
            }
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/games/{id}`

One game: One game, with the score by period.

Plans: Free key and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The game, by its id (gm_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "id": "gm_C513E9BF",
        "competition": {
            "id": "cp_929127FC",
            "name": "Example name"
        },
        "season": {
            "id": "ss_EBC81C6D",
            "name": "Example name"
        },
        "stage": "regular",
        "round": "12",
        "date": "2026-10-01",
        "tip_off": "2026-10-01T19:45:00Z",
        "status": "scheduled",
        "home": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "away": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "home_score": 88,
        "away_score": 81,
        "attendance": 11204,
        "venue": "text",
        "has": {
            "boxscore": true,
            "playbyplay": true,
            "shots": true
        },
        "periods": {
            "home": [
                12
            ],
            "away": [
                12
            ]
        },
        "officials": [
            {
                "name": "Example name",
                "role": "referee"
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/games/{id}/boxscore`

Box score: Every player line and both team lines.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The game, by its id (gm_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "game": {
            "id": "gm_C513E9BF",
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "season": {
                "id": "ss_EBC81C6D",
                "name": "Example name"
            },
            "stage": "regular",
            "round": "12",
            "date": "2026-10-01",
            "tip_off": "2026-10-01T19:45:00Z",
            "status": "scheduled",
            "home": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "away": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "home_score": 88,
            "away_score": 81,
            "attendance": 11204,
            "venue": "text",
            "has": {
                "boxscore": true,
                "playbyplay": true,
                "shots": true
            }
        },
        "home": {
            "team": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "coach": "Coach name",
            "totals": {
                "points": 2,
                "two_made": 12,
                "two_attempted": 12,
                "three_made": 12,
                "three_attempted": 12,
                "free_throws_made": 12,
                "free_throws_attempted": 12,
                "offensive_rebounds": 12,
                "defensive_rebounds": 12,
                "rebounds": 12,
                "assists": 12,
                "steals": 12,
                "turnovers": 12,
                "blocks": 12,
                "blocks_received": 12,
                "fouls": 12,
                "fouls_drawn": 12,
                "performance_index": 12,
                "field_goals_made": 12,
                "field_goals_attempted": 12
            },
            "players": [
                {
                    "player": {},
                    "number": "23",
                    "starter": true,
                    "played": true,
                    "minutes": "31:12",
                    "seconds": 1872,
                    "points": 2,
                    "two_made": 12,
                    "two_attempted": 12,
                    "three_made": 12,
                    "three_attempted": 12,
                    "free_throws_made": 12,
                    "free_throws_attempted": 12,
                    "offensive_rebounds": 12,
                    "defensive_rebounds": 12,
                    "rebounds": 12,
                    "assists": 12,
                    "steals": 12,
                    "turnovers": 12,
                    "blocks": 12,
                    "blocks_received": 12,
                    "fouls": 12,
                    "fouls_drawn": 12,
                    "performance_index": 12,
                    "field_goals_made": 12,
                    "field_goals_attempted": 12,
                    "plus_minus": 12
                }
            ]
        },
        "away": {
            "team": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "coach": "Coach name",
            "totals": {
                "points": 2,
                "two_made": 12,
                "two_attempted": 12,
                "three_made": 12,
                "three_attempted": 12,
                "free_throws_made": 12,
                "free_throws_attempted": 12,
                "offensive_rebounds": 12,
                "defensive_rebounds": 12,
                "rebounds": 12,
                "assists": 12,
                "steals": 12,
                "turnovers": 12,
                "blocks": 12,
                "blocks_received": 12,
                "fouls": 12,
                "fouls_drawn": 12,
                "performance_index": 12,
                "field_goals_made": 12,
                "field_goals_attempted": 12
            },
            "players": [
                {
                    "player": {},
                    "number": "23",
                    "starter": true,
                    "played": true,
                    "minutes": "31:12",
                    "seconds": 1872,
                    "points": 2,
                    "two_made": 12,
                    "two_attempted": 12,
                    "three_made": 12,
                    "three_attempted": 12,
                    "free_throws_made": 12,
                    "free_throws_attempted": 12,
                    "offensive_rebounds": 12,
                    "defensive_rebounds": 12,
                    "rebounds": 12,
                    "assists": 12,
                    "steals": 12,
                    "turnovers": 12,
                    "blocks": 12,
                    "blocks_received": 12,
                    "fouls": 12,
                    "fouls_drawn": 12,
                    "performance_index": 12,
                    "field_goals_made": 12,
                    "field_goals_attempted": 12,
                    "plus_minus": 12
                }
            ]
        }
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/games/{id}/playbyplay`

Play by play: Every event in order, with the clock and running score.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The game, by its id (gm_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "game": {
            "id": "gm_C513E9BF",
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "season": {
                "id": "ss_EBC81C6D",
                "name": "Example name"
            },
            "stage": "regular",
            "round": "12",
            "date": "2026-10-01",
            "tip_off": "2026-10-01T19:45:00Z",
            "status": "scheduled",
            "home": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "away": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "home_score": 88,
            "away_score": 81,
            "attendance": 11204,
            "venue": "text",
            "has": {
                "boxscore": true,
                "playbyplay": true,
                "shots": true
            }
        },
        "events": [
            {
                "seq": 412,
                "period": 4,
                "clock": "05:42",
                "side": "home",
                "team": {
                    "id": "tm_8EB4D858"
                },
                "player": {
                    "id": "pl_EDA561C6",
                    "name": "Example name"
                },
                "type": "two_made",
                "description": "made a three",
                "distance_ft": 12,
                "home_score": 88,
                "away_score": 81
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/games/{id}/shots`

Shots: Every shot, with where it was taken from and whether it went in.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The game, by its id (gm_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "game": {
            "id": "gm_C513E9BF",
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "season": {
                "id": "ss_EBC81C6D",
                "name": "Example name"
            },
            "stage": "regular",
            "round": "12",
            "date": "2026-10-01",
            "tip_off": "2026-10-01T19:45:00Z",
            "status": "scheduled",
            "home": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "away": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "home_score": 88,
            "away_score": 81,
            "attendance": 11204,
            "venue": "text",
            "has": {
                "boxscore": true,
                "playbyplay": true,
                "shots": true
            }
        },
        "shots": [
            {
                "seq": 412,
                "period": 4,
                "side": "text",
                "team": {
                    "id": "tm_8EB4D858"
                },
                "player": {
                    "id": "pl_EDA561C6",
                    "name": "Example name"
                },
                "value": 3,
                "made": true,
                "points": 2,
                "x_ft": -7.2,
                "y_ft": 14.5,
                "distance_ft": 16.2,
                "fastbreak": true,
                "second_chance": true,
                "off_turnover": true,
                "at": "2026-10-01T19:45:00Z"
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/results/yesterday`

Yesterday's results: Yesterday's finished games.

Plans: Free key and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "gm_C513E9BF",
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "season": {
                "id": "ss_EBC81C6D",
                "name": "Example name"
            },
            "stage": "regular",
            "round": "12",
            "date": "2026-10-01",
            "tip_off": "2026-10-01T19:45:00Z",
            "status": "scheduled",
            "home": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "away": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "home_score": 88,
            "away_score": 81,
            "attendance": 11204,
            "venue": "text",
            "has": {
                "boxscore": true,
                "playbyplay": true,
                "shots": true
            }
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

### Players

Players: search, game logs and season averages.

#### `GET /v1/players/{id}`

One player: One player, with the teams played for.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The player, by its id (pl_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "id": "pl_EDA561C6",
        "name": "Example name",
        "birth_date": "2026-10-01",
        "height_cm": 12,
        "weight_kg": 12,
        "country": "ES",
        "position": "text",
        "games": 34,
        "teams": [
            {
                "id": "tm_8EB4D858",
                "name": "Example name",
                "games": 34,
                "first_date": "2026-10-01",
                "last_date": "2026-10-01"
            }
        ],
        "awards": [
            {
                "name": "Example name",
                "year": 12
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/players/{id}/games`

Player game log: A player's game log: one box line per game.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The player, by its id (pl_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `from` | query | date | no | The first day, as YYYY-MM-DD. |
| `to` | query | date | no | The last day, as YYYY-MM-DD. |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": [
        {
            "game": {
                "id": "gm_C513E9BF",
                "date": "2026-10-01"
            },
            "team": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            },
            "opponent": {
                "id": "tm_8EB4D858"
            },
            "home": true,
            "starter": true,
            "played": true,
            "minutes": "31:12",
            "points": 2,
            "two_made": 12,
            "two_attempted": 12,
            "three_made": 12,
            "three_attempted": 12,
            "free_throws_made": 12,
            "free_throws_attempted": 12,
            "offensive_rebounds": 12,
            "defensive_rebounds": 12,
            "rebounds": 12,
            "assists": 12,
            "steals": 12,
            "turnovers": 12,
            "blocks": 12,
            "blocks_received": 12,
            "fouls": 12,
            "fouls_drawn": 12,
            "performance_index": 12,
            "field_goals_made": 12,
            "field_goals_attempted": 12,
            "plus_minus": 12
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/players`

Find players: Find players by name or team, with the games they played and their last team. Send q (3 letters or more) or team.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name. |
| `team` | query | id | no | Only this team, by its id (tm_…). |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "pl_EDA561C6",
            "name": "Example name",
            "games": 34,
            "first_date": "2026-10-01",
            "last_date": "2026-10-01",
            "last_team": {
                "id": "tm_8EB4D858",
                "name": "Example name"
            }
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/players/{id}/seasons`

Player seasons: A player's averages in each season, team and competition played.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The player, by its id (pl_…). |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "player": {
            "id": "pl_EDA561C6",
            "name": "Example name"
        },
        "seasons": [
            {
                "season": {
                    "id": "ss_EBC81C6D",
                    "name": "Example name"
                },
                "competition": {
                    "id": "cp_929127FC",
                    "name": "Example name"
                },
                "team": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "games": 34,
                "starts": 12,
                "minutes": 7.5,
                "points": 7.5,
                "rebounds": 7.5,
                "assists": 7.5,
                "steals": 7.5,
                "blocks": 7.5,
                "turnovers": 7.5,
                "field_goal_pct": 7.5,
                "three_pct": 7.5,
                "free_throw_pct": 7.5
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

### Stats

Standings, leaders, head to head, team form, player splits and betting trends, worked out from the games and prices.

#### `GET /v1/teams/{id}/form`

Team form: A team's last games with margin, pace and ratings.

Plans: Complete and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The team, by its id (tm_…). |
| `last` | query | integer | no | How many recent games, from 1 to 50. 10 if left out. |
| `venue` | query | enum | no | home or away: only those games. |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "team": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "summary": {
            "games": 34,
            "won": 12,
            "lost": 12,
            "average_margin": 7.5,
            "pace": 7.5,
            "offensive_rating": 7.5,
            "defensive_rating": 7.5
        },
        "games": [
            {
                "game": {
                    "id": "gm_C513E9BF",
                    "date": "2026-10-01",
                    "competition": {}
                },
                "venue": "home",
                "opponent": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "result": "W",
                "points_for": 12,
                "points_against": 12,
                "margin": 12,
                "possessions": 7.5,
                "pace": 7.5,
                "offensive_rating": 7.5,
                "defensive_rating": 7.5
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/players/{id}/splits`

Player splits: A player's averages split home and away, by result, month, opponent or starting role.

Plans: Complete and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The player, by its id (pl_…). |
| `by` | query | enum | no | How to split: venue (the default), result, month, opponent or starter. |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "player": {
            "id": "pl_EDA561C6",
            "name": "Example name"
        },
        "by": "text",
        "splits": [
            {
                "split": "text",
                "opponent": "text",
                "games": 34,
                "minutes": 7.5,
                "points": 7.5,
                "rebounds": 7.5,
                "assists": 7.5,
                "steals": 7.5,
                "turnovers": 7.5,
                "blocks": 7.5,
                "field_goal_pct": 7.5,
                "three_pct": 7.5,
                "free_throw_pct": 7.5,
                "true_shooting_pct": 7.5,
                "usage_pct": 7.5
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/standings`

Standings: A season's table from its regular-season final scores: played, won, lost, points for and against, home, away, last ten and streak.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `competition` | query | id | yes | Only this competition, by its id (cp_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": {
        "competition": {
            "id": "cp_929127FC",
            "name": "Example name"
        },
        "season": {
            "id": "ss_EBC81C6D",
            "name": "Example name"
        },
        "games": 34,
        "through": "2026-10-01",
        "table": [
            {
                "rank": 12,
                "team": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "played": 12,
                "won": 12,
                "lost": 12,
                "win_share": 7.5,
                "points_for": 12,
                "points_against": 12,
                "points_difference": 12,
                "home": "text",
                "away": "text",
                "last_ten": "text",
                "streak": "text"
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/teams/{id}/head-to-head`

Head to head: Two teams' meetings: the record from the first team's side, home and away, average score and the last games.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The team, by its id (tm_…). |
| `opponent` | query | id | yes | Only this team, by its id (tm_…). |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `last` | query | integer | no | How many recent games, from 1 to 50. 10 if left out. |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "team": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "opponent": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "summary": {
            "games": 34,
            "won": 12,
            "lost": 12,
            "home": "text",
            "away": "text",
            "average_points_for": 7.5,
            "average_points_against": 7.5,
            "first_date": "2026-10-01",
            "last_date": "2026-10-01"
        },
        "games": [
            {
                "id": "gm_C513E9BF",
                "competition": {
                    "id": "cp_929127FC",
                    "name": "Example name"
                },
                "season": {
                    "id": "ss_EBC81C6D",
                    "name": "Example name"
                },
                "stage": "regular",
                "round": "12",
                "date": "2026-10-01",
                "tip_off": "2026-10-01T19:45:00Z",
                "status": "scheduled",
                "home": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "away": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "home_score": 88,
                "away_score": 81,
                "attendance": 11204,
                "venue": "text",
                "has": {
                    "boxscore": true,
                    "playbyplay": true,
                    "shots": true
                }
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/stats/leaders`

Leaders: A season's leaders in one statistic, per game. Leave season out for the competition's latest season with box scores.

Plans: Complete and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `competition` | query | id | yes | Only this competition, by its id (cp_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `stat` | query | enum | no | One of: points, rebounds, assists, steals, blocks, three_made, offensive_rebounds, minutes, performance_index. |
| `min_games` | query | integer | no | Leave out angles with fewer games than this. 30 if left out. |
| `top` | query | integer | no |  |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": {
        "competition": {
            "id": "cp_929127FC",
            "name": "Example name"
        },
        "season": {
            "id": "ss_EBC81C6D",
            "name": "Example name"
        },
        "stat": "text",
        "min_games": 12,
        "leaders": [
            {
                "rank": 12,
                "player": {
                    "id": "pl_EDA561C6",
                    "name": "Example name"
                },
                "team": {
                    "id": "tm_8EB4D858",
                    "name": "Example name"
                },
                "games": 34,
                "per_game": 7.5,
                "total": 12
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

### Reference

Competitions, seasons and teams: the ids everything else is asked by.

#### `GET /v1/competitions`

Competitions: Every competition held, with its seasons and games.

Plans: Free key and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "cp_929127FC",
            "name": "Example name",
            "slug": "example-league",
            "country": "ES",
            "gender": "men",
            "kind": "league",
            "seasons": 12,
            "first_season": "2000-01",
            "last_season": "2025-26",
            "games": 34
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/seasons`

Seasons: Seasons of a competition, newest first.

Plans: Free key and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "ss_EBC81C6D",
            "name": "Example name",
            "start_year": 2025,
            "competition": {
                "id": "cp_929127FC",
                "name": "Example name"
            },
            "games": 34,
            "first_date": "2026-10-01",
            "last_date": "2026-10-01"
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/teams`

Teams: Teams, by competition and season.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `competition` | query | id | no | Only this competition, by its id (cp_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |
| `q` | query | string | no | Part of a name. |
| `page` | query | integer | no | Which page, from 1. |
| `cursor` | query | string | no | The next_cursor from the last answer, to carry on. |
| `per_page` | query | integer | no | Records an answer, from 1 to 200. 50 if left out. |

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": [
        {
            "id": "tm_8EB4D858",
            "name": "Example name",
            "country": "ES",
            "games": 34
        }
    ],
    "meta": {
        "count": 1,
        "next_cursor": null,
        "page": 1,
        "per_page": 50,
        "total": 1,
        "total_pages": 1,
        "next_page": null,
        "prev_page": null,
        "plan": "Free key"
    }
}
```

#### `GET /v1/teams/{id}`

One team: One team: its country, the club's city, home arena, arena capacity and founding year where known, and the competitions and seasons it played.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The team, by its id (tm_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "id": "tm_8EB4D858",
        "name": "Example name",
        "country": "ES",
        "city": "text",
        "arena": "text",
        "arena_capacity": 12,
        "founded": 12,
        "coaches": [
            {
                "name": "Example name",
                "from": 12,
                "to": 12
            }
        ],
        "competitions": [
            {
                "id": "cp_929127FC",
                "name": "Example name",
                "seasons": [
                    {}
                ]
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

#### `GET /v1/teams/{id}/roster`

Team roster: Every player who played for a team in a season, with games, starts and averages. Leave season out for the team's latest.

Plans: Live and up.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | id | yes | The team, by its id (tm_…). |
| `season` | query | id | no | Only this season, by its id (ss_…). |

Errors: 400, 422, 401, 403, 429, 404.

Example answer, in shape:

```json
{
    "data": {
        "team": {
            "id": "tm_8EB4D858",
            "name": "Example name"
        },
        "season": {
            "id": "ss_EBC81C6D",
            "name": "Example name"
        },
        "competition": {
            "id": "cp_929127FC",
            "name": "Example name"
        },
        "players": [
            {
                "player": {
                    "id": "pl_EDA561C6",
                    "name": "Example name"
                },
                "number": "23",
                "games": 34,
                "starts": 12,
                "last_game": "2026-10-01",
                "minutes": 7.5,
                "points": 7.5,
                "rebounds": 7.5,
                "assists": 7.5,
                "steals": 7.5,
                "blocks": 7.5,
                "turnovers": 7.5,
                "field_goal_pct": 7.5,
                "three_pct": 7.5,
                "free_throw_pct": 7.5
            }
        ]
    },
    "meta": {
        "plan": "Free key"
    }
}
```

### Account

Your own key: plan, calls and limits.

#### `GET /v1/usage`

Usage: Your plan, calls today and this month, limits and the days your plan reaches. Not counted.

Plans: Free key and up.

Errors: 400, 422, 401, 403, 429.

Example answer, in shape:

```json
{
    "data": {
        "key": "bba_live_7f3c",
        "plan": "Free key",
        "calls_today": 37,
        "calls_this_month": 412,
        "limits": {
            "per_minute": 12,
            "per_day": 12,
            "per_month": 12
        },
        "remaining": 63,
        "resets_at": "2026-10-03T00:00:00Z",
        "window": {
            "from": "2026-10-01",
            "to": "2026-10-01"
        }
    },
    "meta": {
        "plan": "Free key"
    }
}
```

## Guides

### Quick start

From no key to your first answer in a few minutes. https://basketballapi.net/documentation/quick-start

### 1. Get a key

Sign up at [basketballapi.net/signup](https://basketballapi.net/signup) with your Google account. Your key, which starts `bba_live_`, is shown straight away and only once: copy it somewhere safe.

### 2. Make your first call

Every call is a GET to `https://api.basketballapi.net/v1` with your key in the `Authorization` header.

```
curl https://api.basketballapi.net/v1/results/yesterday \
  -H "Authorization: Bearer bba_live_your_key"
```

The same in Python:

```
import requests

r = requests.get("https://api.basketballapi.net/v1/results/yesterday",
                 headers={"Authorization": "Bearer bba_live_your_key"})
for g in r.json()["data"]:
    print(g["home"]["name"], g["home_score"], g["away_score"], g["away"]["name"])
```

### 3. Read the answer

Every answer has the same two parts: `data`, the records you asked for, and `meta`, which says where you are in a list and which plan answered.

```
{
  "data": [ { "id": "gm_7q3m1abc", "date": "2026-10-01", "status": "final", ... } ],
  "meta": { "count": 25, "next_cursor": "eyJvIjoyNX0", "page": 1, "per_page": 50, "plan": "Free key" }
}
```

### 4. Follow the ids

Every record has an id with a short prefix that says what it is: `cp_` a competition, `ss_` a season, `tm_` a team, `gm_` a game, `pl_` a player. Take a game id from a list and ask for its box score, play by play or shots:

```
curl https://api.basketballapi.net/v1/games/gm_7q3m1abc/boxscore \
  -H "Authorization: Bearer bba_live_your_key"
```

### Next

- [Authentication](https://basketballapi.net/documentation/authentication): the two headers a key can go in.
- [Limits and quotas](https://basketballapi.net/documentation/limits): what your plan allows and how to read what is left.
- [Paging](https://basketballapi.net/documentation/paging): walking through long lists.
- [Errors](https://basketballapi.net/documentation/errors): every error code and what to do about it.

### Authentication

Where your key goes, and how to keep it safe. https://basketballapi.net/documentation/authentication

### Send your key in a header

Either of these works:

```
Authorization: Bearer bba_live_your_key
X-API-Key: bba_live_your_key
```

A key in the address (`?key=`, `?api_key=`) is refused with a `400 bad_request`, because addresses end up in logs and browser history.

### Keys are shown once

We keep only a fingerprint of each key, never the key itself, so it is shown once when it is made. Lost it? Make a new key from your [dashboard](https://basketballapi.net/dashboard/keys) and revoke the old one.

### Several keys, one account

An account can have up to 5 active keys, for example one per server. They all share your plan and its daily limit. Label them on the dashboard so you can tell them apart, and revoke any key the moment it leaks: calls with it stop at once.

### From a browser

The API answers from any origin, so you can call it from a page. Do not put your key in a public page, though: anyone can read it there. Call the API from your own server and pass on what your page needs.

### No key needed

`GET /v1/` and `GET /v1/openapi.json` answer without a key.

### Limits and quotas

Calls a day, calls a minute, how far back each plan reaches, and the headers that tell you what is left. https://basketballapi.net/documentation/limits

### What each plan allows

| Plan | Calls a day | Calls a minute | Reaches |
| --- | --- | --- | --- |
| Free key | 100 | 10 | Yesterday and today |
| Live | 10,000 | 60 | The last 12 months |
| Archive | 50,000 | 60 | Every season |
| Complete | 250,000 | 120 | Every season |

The daily limit is shared by every key on your account and resets at 00:00 UTC. `GET /v1/usage` tells you where you stand and does not count as a call.

### The headers on every answer

| Header | What it says |
| --- | --- |
| `X-RateLimit-Limit` | Calls a minute on your plan. |
| `X-RateLimit-Remaining` | Calls left this minute. |
| `X-RateLimit-Reset` | When this minute ends, as a Unix time. |
| `X-Quota-Remaining` | Calls left today. |
| `Retry-After` | On a 429 only: seconds to wait before trying again. |

### When you reach a limit

- `429 rate_limited`: too many calls this minute. Wait the seconds in `Retry-After`.
- `429 quota_exceeded`: today's calls are used up. The answer says when the allowance resets, in `resets_at`.

Only answers that succeed count towards your daily limit; errors do not.

### Dates outside your plan

Asking for a game or a day your plan does not reach answers `403 upgrade_required`, naming the plan that does. The same goes for an endpoint your plan does not include.

### Paging

Walking through long lists with page numbers or a cursor. https://basketballapi.net/documentation/paging

### Lists come in pages

Endpoints that return a list answer 50 records at a time. Ask for up to 200 with `per_page`.

### Two ways to move on

- **A cursor** (fastest): send `cursor` with the `next_cursor` from the last answer, until it comes back as `null`. A cursor answer counts nothing, so it stays quick on big lists.
- **Page numbers**: send `page=2`, `page=3` and so on. The first answer says `total` and `total_pages`.

```
GET /v1/games?competition=cp_4f2k9qxa&per_page=200
GET /v1/games?competition=cp_4f2k9qxa&per_page=200&cursor=eyJvIjoyMDAsIm4iOjIwMH0
```

### What meta carries

| Field | Meaning |
| --- | --- |
| `count` | Records in this answer. |
| `next_cursor` | Send it as `cursor` for the next records, or `null` at the end. |
| `page`, `per_page` | Where you are. |
| `total`, `total_pages` | How many there are (not sent on a cursor answer). |
| `next_page`, `prev_page` | The neighbouring page numbers, or `null`. |

### Errors

Every error code, what it means and what to do about it. https://basketballapi.net/documentation/errors

### One shape for every error

```
{
  "error": {
    "code": "quota_exceeded",
    "message": "This key has used its 100 calls for today. The allowance resets at 2026-10-03T00:00:00Z.",
    "resets_at": "2026-10-03T00:00:00Z",
    "docs": "https://basketballapi.net/documentation/errors"
  }
}
```

Switch on `code`: codes never change. `message` is a plain sentence you can show as it is, and may be reworded.

### The codes

| HTTP | Code | What to do |
| --- | --- | --- |
| 400 | `bad_request` | A value is wrong, such as a date that is not a date. The message names it. |
| 401 | `unauthorized` | No key, or a key that is not valid or was revoked. Check the header. |
| 403 | `upgrade_required` | The endpoint or the date is on another plan. The answer names it in `plan`, with a link in `pricing`. |
| 404 | `not_found` | No record with that id, or no such endpoint. |
| 422 | `unknown_parameter` | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | `rate_limited` | Too many calls this minute. Wait the seconds in `Retry-After`. |
| 429 | `quota_exceeded` | Today's calls are used up. Try again after `resets_at`, or move to a bigger plan. |
| 500 | `server_error` | Something went wrong on our side. It is logged; try again shortly. |

### Retrying

Retry a 429 after `Retry-After` and a 500 after a short wait. Never retry a 400, 401, 403, 404 or 422 unchanged: the same request fails the same way.

### Webhooks

Final scores and finished periods posted to your server as they happen. https://basketballapi.net/documentation/webhooks

### What is sent

| Event | When | Plans |
| --- | --- | --- |
| `game.final` | A game has its final score. | Live and up |
| `game.period` | A period of a game in progress has ended. | Live and up |

Each event is one POST of JSON to your address, at most a minute or two after it happens. The body is the same shape for every event:

```
{
  "id": "evt_5c1f0a9e2b7d4c18",
  "type": "game.final",
  "created_at": "2026-10-01T20:47:12Z",
  "data": { "game": { "id": "gm_tawfgjqt", "home_score": 82, "away_score": 78, ... } }
}
```

### Add a webhook

```
curl -X POST https://api.basketballapi.net/v1/webhooks \
  -H "Authorization: Bearer bba_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://you.example/hooks/basketball", "events": ["game.final", "game.period"]}'
```

Leave out `events` for all of them, and add `competitions`, a list of competition ids, to hear about those only. The answer carries the webhook's `secret`, once: keep it to check signatures. An account holds up to 10 webhooks.

- `GET /v1/webhooks`: your webhooks, with the last 24 hours of deliveries.
- `POST /v1/webhooks/{id}/test`: send the newest real `game.final` now, marked `"test": true`, and see what your server answered.
- `DELETE /v1/webhooks/{id}`: remove one.

### Check the signature

Every request carries `X-BBA-Signature: t=1759351632,v1=5f2b...`: the time it was sent and an HMAC-SHA256, with your secret, of the time, a dot and the raw body. Check it, and refuse a time more than five minutes old.

```
import hmac, hashlib, time

def verify(secret, header, body):
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    want = hmac.new(secret.encode(), (parts["t"] + "." + body).encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(want, parts["v1"])
```

The request also carries `X-BBA-Event` and `X-BBA-Delivery`, the event id, which stays the same on a retry: use it to skip one you have already handled.

### Answering and retries

Answer with any 2xx status within 10 seconds. A timeout, a 5xx, a 408 or a 429 is tried again, 8 tries in all over about three days. Any other 4xx tells us not to: that delivery stops there. A webhook whose deliveries fail 20 times in a row is turned off and we email you; add it again once your server answers.

Addresses must be https on port 443 and reachable from the internet; redirects are not followed.

### Seasons, stages and standings

How a season is named, what each game stage and status means, how standings are worked out, and how box scores relate to the final score. https://basketballapi.net/documentation/stages

### Seasons

A season belongs to one competition and is named by its years: `2025-26` for a winter league, `2026` for one played inside a calendar year, such as the WNBA. `start_year` is the year it began. List a competition's seasons with `GET /v1/seasons?competition=`, newest first.

### Game status

| Status | Means |
| --- | --- |
| `scheduled` | Still to come, or played in the last few days and waiting for its score. |
| `final` | Played, with both scores. |
| `no_result` | No score and none to come: called off, abandoned, decided by forfeit, postponed and not replayed, or never reported. |

Every game has one of these three. A postponed game stays `scheduled` until a week after its day; if it has not been played by then it becomes `no_result`.

### Game stage

| Stage | Means | Standings | Form, splits, trends |
| --- | --- | --- | --- |
| `regular` | The regular season. | Counted | Counted |
| `play-in` | A play-in game between the regular season and the play-offs. | Left out | Counted |
| `playoffs` | Play-offs and finals. | Left out | Counted |
| `preseason` | Pre-season games. | Left out | Left out |
| `all-star` | All-Star and rising-stars games. | Left out | Left out |

A few competitions name their own stages, such as `final four` or `cup`; these are left out of standings too. Friendlies are a competition kind of their own (`kind` `friendly`) and are left out of form and splits unless you ask for that competition.

### Standings

`GET /v1/standings?competition=` (Live and up) works a season's table out from its regular-season final scores, so it is never older than the last result we hold. Leave out `season` for the latest one your plan reaches.

- Order: share of games won, then points difference, then points scored. A league's own tie-breakers (head-to-head records, conference rules) are not applied, so two teams level on wins may sit the other way round in the league's own table.
- Each row carries played, won, lost, `win_share`, points for and against, `points_difference`, the home and away records, the last ten and the current `streak`.
- Basketball has no draws: every game counts as a win for one side.
- Leagues played in groups or conferences come back as one table of every team; split it with the teams' own records if you need the groups.

### Box scores and the final score

A box score is kept as the league published it. In nearly every game its points add up to the final score; in a small share of games from a few leagues the league's own sheet is a few points short, and we leave it that way rather than change a player's figures. Take the result from the game's `home_score` and `away_score`, never from adding up the box score.

### Changelog

What changed in the API, newest first. https://basketballapi.net/documentation/changelog

v1 only ever grows: fields and endpoints are added, never renamed. Anything retired is announced here twelve months ahead.

### 9 October 2026

- Teams: `GET /v1/teams/{id}` gains `city`, `arena` (the club's current home arena), `arena_capacity` and `founded`, where known; `null` elsewhere. The MCP server gains `get_team` to read them.
- Prices are withdrawn: `GET /v1/games/{id}/prices` and `GET /v1/stats/trends` no longer answer, `/v1/teams/{id}/form` no longer carries results against the spread and total, and webhooks no longer offer `prices.closing`. The MCP server's `get_prices` and `get_trends` are gone with them. Games, scores and every other part stay.
- Competitions and seasons that hold no games are no longer listed.

### 10 October 2026

- Accounts: signing up and signing in are with Google only. Existing members sign in with the Google account that uses the same email address.
- The free key is now a look at the API: yesterday's and today's games and results (score by quarter included), the competitions with their current season, and your usage. Box scores, players, teams and rosters move to Live and above.
- Documentation: every endpoint page has Try it, which runs the call with your key, and remembers the key in your browser.

### 9 October 2026

- Players: `GET /v1/players/{id}` gains `awards`, the honours a player has received (most valuable player, all-league teams, cup and league titles and more), each with its year where known.
- Teams: `GET /v1/teams/{id}` gains `coaches`, the club's head coaches, latest first, with the years of each spell where known.

### 8 October 2026

- Japan's B.League (B1 and B2): box scores and play by play are withdrawn; its games (date, teams, score) stay.
- Korea's KBL: box scores, play by play and shots are withdrawn; its games (date, teams, score, venue) stay.
- Players: `GET /v1/players/{id}` gains `birth_date`, `height_cm`, `weight_kg` and `country` (nationality as a three-letter IOC code) and `position` (PG, SG, SF, PF, C, G or F, or two joined such as G-F), each `null` where not known. More players are filled in each day.

### 2 October 2026

- New: Brazil's NBB, game by game with full box scores, quarter scores, play by play with the running score, referees, coaches and arena. Seasons fill in over the coming days.
- Spain's Liga Endesa, Copa del Rey and Supercopa: box scores are withdrawn; their games (date, teams, score) stay.
- VTB United League: box scores, play by play and officials are withdrawn; its games (date, teams, score, venue, attendance) stay.
- New: Lithuania's LKL, game by game with full box scores, team extras (points off turnovers, in the paint, second chance, fast break, bench, biggest lead and run, lead changes, ties, time leading), play by play with the running score, referees, coaches, arena and attendance. Seasons fill in over the coming days.
- Games: every game now carries `venue`, the arena where the league names it (Greece's Basket League, Korea's KBL, Lithuania's LKL and Brazil's NBB; `null` elsewhere for now).
- Games: `GET /v1/games/{id}` gains `officials`, the referees (crew chief first) and the commissioner, for VTB United League games where the league names them: nearly every game from 2018-19 on and in 2015-16, 2016-17 and 2009-10, and about a quarter of 2017-18. Other leagues follow as their game sheets allow; `null` where none are named.
- New: `GET /v1/players?q=` finds players by name or team (on every plan, the free key included); `/v1/players/{id}/seasons` gives a player's averages in each season and team; `/v1/teams/{id}/roster` lists everyone who played for a team in a season; `/v1/teams/{id}/head-to-head?opponent=` gives two teams' record and last meetings, from Live; and `/v1/stats/leaders?competition=` ranks a season's leaders per game in points, rebounds, assists and six other figures, on Complete. The MCP server gains `find_players`.
- Games: NBA play-in and play-off games now carry `stage` `play-in` and `playoffs` in every season (some were filed as regular season), so standings count the regular season alone. The NBA Cup final carries `cup`. Australia's NBL play-off games carry `playoffs` back to 1979-80, as do Japan's B1 and B2 championship games in most seasons from 2016-17 and Czechia's NBL play-offs in 1998-99.
- Box scores: ABA League players whose names carry letters such as ş, ğ or ü are now in their team's box score (they were missing from some games), so team points match the final score in all but a handful of games.
- Teams: 68 clubs held under two ids are joined, most of them a European club's cup games and its league games (CSKA Moscow, Žalgiris Kaunas, Unicaja, ALBA Berlin and others), so one team id now carries a club's whole history. An id merged away no longer answers: find the club again with `GET /v1/teams?q=`. US college names are written in full (Mississippi State, not Mississippi St.).
- Competitions: the NBA's summer leagues (Las Vegas, Orlando, Salt Lake City) and the California Classic are filed as friendlies (`kind` `friendly`), so July exhibition games no longer count in NBA teams' form and splits unless you ask for that competition.
- Games: 418 youth and junior games that had been filed under Spain's Liga Endesa are removed, so its tables and team records count league games alone.
- Box scores added: Spain's Liga Endesa, Copa del Rey and Supercopa back to 2020-21 (2,477 games), and the ABA League back to 2001-02 (4,652 games). Korea's KBL is being filled back to 1997-98.
- New from Live: `GET /v1/standings?competition=`, a season's table from its regular-season results, with played, won, lost, points for and against, home, away, last ten and streak. Leave `season` out for the latest. Ordered by share of games won, then points difference; a league's own tie-breakers are not applied.
- Stats: `/v1/teams/{id}/form`, `/v1/players/{id}/splits` and `/v1/stats/trends` now count competitive games only. All-Star and pre-season games stay in the games list (with `stage` `all-star` or `preseason`) but are left out of the stats, and friendlies are left out unless you ask for that competition.
- EuroCup now holds every season from 2002 as one competition; its 2002 to 2008 seasons were listed apart under the old name, ULEB Cup, which is retired.
- Games: a new status, `no_result`, for a game with no score and none to come (called off, abandoned, decided by forfeit, postponed and not replayed, or never reported), so `scheduled` only ever means still to come and every game is `scheduled`, `final` or `no_result`. Filter with `status=no_result`.
- New on Complete: the MCP server at `https://basketballapi.net/mcp`, 14 tools any assistant that speaks MCP can call with your key. See [MCP](https://basketballapi.net/mcp).
- Prices: each moneyline, spread and total market now carries `opening` and `history`, every reading before tip-off with the line most bookmakers showed and the average prices on it, for games from the 2026-27 season.
- Ids now take their lasting form in lower case, such as `gm_88km3vf9`; upper case is still accepted.
- A text parameter longer than 100 characters is answered with a 400.
- Clubs that were listed twice are now one team, and games stored twice are now one game, so a club's history is all in one place.
- New: webhooks for final scores, finished periods and closing prices, from the Live plan. See [Webhooks](https://basketballapi.net/documentation/webhooks).
- New on Complete: `GET /v1/teams/{id}/form` (last games with pace, ratings and results against the closing lines), `GET /v1/players/{id}/splits` (home and away, by result, month, opponent or role) and `GET /v1/stats/trends` (betting angles with their hit rate and return).
- New: `GET /v1/games/{id}/prices`, closing prices from every bookmaker for moneyline, spread, total, three-way and double chance, with each market's result. On Archive and Complete.
- Box scores: team totals now always add up the players' lines and the team's own rebounds, and `played` is true for every player with minutes.
- Shots: free throws now have `value` 1 and no position on the floor.
- Play by play: the start and end of each period carry a clock, and the end of the game appears once.
- Daily limits on every plan, shared by all the keys on an account.
- The free key now reads box scores, players and player game logs for recent games.
- Archive now reaches today's and upcoming games as well as every past season.

### September 2026

- v1 released: competitions, seasons, teams, games, box scores, play by play, shots, players and game logs, yesterday's results, usage and the OpenAPI description.

## About this document

Generated from the API's own endpoint registry, guides and plan settings, never written by hand. The date at the top is the newest change to those sources: two copies with the same date are the same.
Machine-readable: OpenAPI at https://api.basketballapi.net/v1/openapi.json, a Postman collection at https://basketballapi.net/documentation/postman.
