---
title: Tennis API
description: ATP/WTA tournaments, players, matches with set-by-set stats, point-by-point data, rankings and match predictions.
badge: pro
---

# Tennis API

The Tennis API covers ATP and WTA tennis: tournaments, players, live and
historical matches with set-by-set statistics, point-by-point sequences,
official rankings and model-based match predictions.

Base URL: `https://sports.bzzoiro.com/tennis/api/v2/`

> **Tip:** for a task-oriented walkthrough, see the
> [Tennis player profile guide](/docs/guides/tennis-player-profile/). Live
> scores can also be streamed over the
> [tennis WebSocket channel](/docs/websocket/tennis/).

## Access

Requires the **Sports Addon** ($5/month) — it unlocks the tennis, CS2, darts,
hockey, basketball and horse racing APIs plus their MCP servers. Get it at
[/addons/](/addons/). You also need a free account token from
[/register/](/register/).

Send the token on every request:

```bash
Authorization: Token YOUR_API_KEY
```

Without a token you get **401**:

```json
{"error": "authentication required", "code": "authentication_required",
 "detail": "Send Authorization: Token <YOUR_TOKEN> on every request.",
 "register": "https://sports.bzzoiro.com/register/"}
```

With a token but no addon you get **402**:

```json
{"error": "Sports Addon required", "code": "addon_required",
 "detail": "Tennis, CS:GO, darts, hockey, basketball and horse racing APIs require the Sports Addon ($5/mo).",
 "pricing_url": "https://sports.bzzoiro.com/pricing/"}
```

List endpoints paginate with `limit` (default 50, max 200) and `offset`, and
return `{count, next, previous, results}`.

## Endpoints

| Endpoint | Description |
|---|---|
| `GET /tennis/api/v2/tournaments/` | List tournaments (ATP/WTA, category, surface) |
| `GET /tennis/api/v2/tournaments/{id}/` | Tournament detail |
| `GET /tennis/api/v2/players/` | Search/list players with current ranking |
| `GET /tennis/api/v2/players/{id}/` | Player detail |
| `GET /tennis/api/v2/matches/` | List matches (default window: next 7 days) |
| `GET /tennis/api/v2/matches/live/` | Matches in play right now |
| `GET /tennis/api/v2/matches/{id}/` | Match detail with per-set stats |
| `GET /tennis/api/v2/matches/{id}/h2h/` | Head-to-head + recent form |
| `GET /tennis/api/v2/matches/{id}/point-by-point/` | Point-by-point sequence |
| `GET /tennis/api/v2/matches/{id}/odds/` | Match odds (decimal) |
| `GET /tennis/api/v2/predictions/` | Model win probabilities |
| `GET /tennis/api/v2/predictions/{id}/` | One prediction |
| `GET /tennis/api/v2/rankings/` | ATP/WTA rankings |
| `GET /tennis/api/v2/rankings/{id}/` | One ranking row |

The machine-readable schema is public at `/tennis/api/schema/`, with an
interactive UI at [/tennis/api/docs/](/tennis/api/docs/) and a themed explorer
at [/docs/explorer/tennis/](/docs/explorer/tennis/).

## Tournaments

**Query parameters**

| Param | Type | Description |
|---|---|---|
| `circuit` | string | `ATP` or `WTA` |
| `category` | string | Tournament category (e.g. Grand Slam, ATP 1000) |
| `surface` | string | `hard`, `clay`, `grass` |
| `include_inactive` | bool | Include tournaments with no current edition |
| `limit` / `offset` | int | Pagination (default 50, max 200) |

Responses are cached ~5 minutes.

```bash
curl -H "Authorization: Token YOUR_API_KEY" \
  "https://sports.bzzoiro.com/tennis/api/v2/tournaments/?circuit=ATP&surface=clay"
```

```json
{"count": 34, "next": null, "previous": null, "results": [
  {"id": 218, "name": "Rome Masters", "circuit": "ATP",
   "category": "ATP 1000", "surface": "clay"}
]}
```

## Players

**Query parameters**

| Param | Type | Description |
|---|---|---|
| `search` | string | Name search (partial match) |
| `country` | string | ISO country code |
| `gender` | string | `M` or `F` |
| `limit` / `offset` | int | Pagination |

```bash
curl -H "Authorization: Token YOUR_API_KEY" \
  "https://sports.bzzoiro.com/tennis/api/v2/players/?search=alcaraz"
```

```json
{"count": 1, "results": [
  {"id": 4211, "name": "Carlos Alcaraz", "short_name": "Alcaraz C.",
   "country_code": "ES", "country_name": "Spain", "gender": "M",
   "current_ranking": {"position": 2, "points": 8805, "type": "ATP"}}
]}
```

Both the list and `/players/{id}/` detail also carry `birthplace`,
`residence`, `prize_current_usd`, `prize_total_usd` and `turned_pro` — `null`
when not recorded upstream.

## Matches

**Query parameters**

| Param | Type | Description |
|---|---|---|
| `tournament` | int | Filter by tournament id |
| `player` | int | Matches involving this player id |
| `status` | string | `upcoming`, `live`, `finished` |
| `date_from` / `date_to` | date | `YYYY-MM-DD`; without dates the list defaults to the next 7 days |
| `limit` / `offset` | int | Pagination |

```bash
curl -H "Authorization: Token YOUR_API_KEY" \
  "https://sports.bzzoiro.com/tennis/api/v2/matches/?player=4211&status=finished&date_from=2026-07-01"
```

```json
{"count": 6, "results": [
  {"id": 36835,
   "tournament": {"id": 218, "name": "Rome Masters", "surface": "clay"},
   "player1": {"id": 4211, "name": "Carlos Alcaraz", "country_code": "ES"},
   "player2": {"id": 3982, "name": "Jannik Sinner", "country_code": "IT"},
   "match_date": "2026-07-19T13:00:00+00:00", "status": "finished",
   "round_name": "Final", "player1_sets": 2, "player2_sets": 1,
   "sets_detail": "6-4, 3-6, 7-5", "winner_id": 4211,
   "odds_player1": 1.95, "odds_player2": 1.87}
]}
```

`GET /matches/live/` returns the same shape for in-play matches only and is
cached 30 seconds. `GET /matches/{id}/` adds full per-set statistics (aces,
double faults, serve percentages per set).

### Head-to-head

`GET /matches/{id}/h2h/` returns previous meetings between the two players
plus each player's last five results.

### Point-by-point

`GET /matches/{id}/point-by-point/` returns the point sequence per game —
useful for momentum charts and pressure analysis.

### Match odds

`GET /matches/{id}/odds/` returns decimal odds for the match winner market:

```json
{"match_id": 36835, "odds_player1": 1.95, "odds_player2": 1.87}
```

## Predictions

Model-based win probabilities for upcoming matches.

**Query parameters**

| Param | Type | Description |
|---|---|---|
| `match` | int | Prediction for one match id |
| `upcoming` | bool | Only matches not yet started |
| `date_from` / `date_to` | date | `YYYY-MM-DD` |
| `limit` / `offset` | int | Pagination |

```json
{"count": 41, "results": [
  {"id": 9917, "match_id": 36901, "player1_win_prob": 0.64,
   "player2_win_prob": 0.36, "predicted_winner_id": 4211,
   "confidence": 0.64}
]}
```

## Rankings

**Query parameters**

| Param | Type | Description |
|---|---|---|
| `type` | string | `ATP` or `WTA` |
| `date` | date | Ranking snapshot date (`YYYY-MM-DD`); default latest |
| `limit` / `offset` | int | Pagination |

Cached 5 minutes.

```bash
curl -H "Authorization: Token YOUR_API_KEY" \
  "https://sports.bzzoiro.com/tennis/api/v2/rankings/?type=WTA&limit=3"
```

```json
{"count": 500, "results": [
  {"id": 88001, "position": 1, "points": 10331, "type": "WTA",
   "player": {"id": 5120, "name": "Aryna Sabalenka", "country_code": "BY"}}
]}
```
