Growing Discord community — direct access to the developer, live coverage & picks. Join now →
Tennis API · v2

Free tennis data API.

REST endpoints for ATP/WTA matches, tournaments, players, rankings, and ML predictions, plus an MCP server for Claude/ChatGPT/Gemini. No rate limit. No credit card.

Quickstart

Three steps to your first request:

  1. Register at sports.bzzoiro.com/register/ — free, no credit card.
  2. Copy the API token from your dashboard.
  3. Send it as Authorization: Token YOUR_TOKEN on any request below.
# Live tennis matches with set-by-set scores curl -H "Authorization: Token YOUR_TOKEN" \ "https://sports.bzzoiro.com/tennis/api/v2/matches/live/"

Authentication

Pass your token on every request via the Authorization header:

Authorization: Token YOUR_TOKEN

Tokens never expire. Keep them secret. If a token leaks, regenerate it from the dashboard.

Base URL

Base URL
https://sports.bzzoiro.com/tennis
Alias (301 redirect)
https://tennis.bzzoiro.com → /tennis
API prefix
/tennis/api/v2/

Pagination

List endpoints use limit + offset query parameters and return:

{ "count": 408, "next": "https://sports.bzzoiro.com/tennis/api/v2/tournaments/?limit=50&offset=50", "previous": null, "results": [/* … */] }
  • limit — page size. Default 50, max 200 (rankings: max 500).
  • offset — number of items to skip. Default 0.

Tournaments

Active tournaments — every tier from Grand Slams down to Challengers and ITFs.

GET /api/v2/tournaments/ List

Paginated list of tennis tournaments. Active-only by default.

ParameterTypeDescription
circuitstringATP or WTA (case-insensitive)
categorystringgrand_slam, masters_1000, atp_500, atp_250, wta_1000, wta_500, wta_250
surfacestringhard, clay, grass, carpet
include_inactivebooleanInclude inactive tournaments. Default false.
limit / offsetintPagination (default 50, max 200)
GET /api/v2/tournaments/{id}/ Detail

Full detail for a single tournament. Cached 5 min.

Players

Player profiles across both tours, with current ranking and biographical data.

GET /api/v2/players/ List

Paginated player list. Each player includes their current ranking.

ParameterTypeDescription
genderstringM or F
countrystringISO 3166-1 alpha-2 country code (e.g. ES, US)
searchstringCase-insensitive name fragment
limit / offsetintPagination (default 50, max 200)
# Top male Spanish players curl -H "Authorization: Token YOUR_TOKEN" \ "https://sports.bzzoiro.com/tennis/api/v2/players/?gender=M&country=ES&limit=10"
GET /api/v2/players/{id}/ Detail

Full profile: name, country, height, weight, plays (right/left), turned-pro year, current ranking. Cached 5 min.

Matches

Tennis matches with set-by-set scores, serve stats, and live snapshots.

GET /api/v2/matches/ List

Paginated list. With no date filter, defaults to the next 7 days.

ParameterTypeDescription
date_from / date_todateYYYY-MM-DD bounds
tournamentint / strTournament ID or name fragment
playerint / strPlayer ID or name fragment
statusstringscheduled, live, finished, cancelled, postponed
limit / offsetintPagination
GET /api/v2/matches/live/ Live

Only currently in-progress matches with the live snapshot: current_set, current_game_p1, current_game_p2, current_point (e.g. "40-30"), is_serving_p1. Cached 30 seconds.

GET /api/v2/matches/{id}/ Detail

Full match details including sets_detail (per-set breakdown), live state (if in-progress), and per-player serve stats: aces, double faults, first/second serve %.

{ "id": 33405, "tournament": { "name": "ATP Rome Masters", "surface": "clay" }, "player1": { "name": "Carlos Alcaraz", "current_ranking": { "position": 2, "type": "ATP" } }, "player2": { "name": "Jannik Sinner", "current_ranking": { "position": 1, "type": "ATP" } }, "status": "finished", "player1_sets": 2, "player2_sets": 1, "sets_detail": [{"p1":6,"p2":4}, {"p1":4,"p2":6}, {"p1":7,"p2":5}], "p1_aces": 12, "p2_aces": 8, "p1_first_serve_pct": 68, "p2_first_serve_pct": 71 }

Predictions

ML predictions calibrated against historical accuracy. XGBoost backbone.

GET /api/v2/predictions/ List

Paginated predictions. Defaults to upcoming.

ParameterTypeDescription
upcomingbooleanDefault true. Set false for past predictions.
date_from / date_todateYYYY-MM-DD bounds
limit / offsetintPagination
GET /api/v2/predictions/{id}/ Detail

Each prediction returns:

  • prob_player1_wins, prob_player2_wins — match winner probabilities (0–100)
  • predicted_winner — 1 or 2
  • confidence — model self-rated confidence (0–100)
  • expected_total_sets, prob_over_2_5_sets
  • expected_total_games, prob_over_20_5_games, prob_over_21_5_games, prob_over_22_5_games
  • prob_player1_wins_first_set
  • actual_winner, was_winner_correct — populated after the match ends

Rankings

ATP & WTA weekly snapshots. Each row carries the previous week's position + points and the player's career best.

GET /api/v2/rankings/ List

Latest snapshot by default. Pass date for a historical snapshot.

ParameterTypeDescription
typestringATP (default) or WTA
datedateYYYY-MM-DD snapshot date
limit / offsetintPagination (max 500)
# Current ATP top 10 curl -H "Authorization: Token YOUR_TOKEN" \ "https://sports.bzzoiro.com/tennis/api/v2/rankings/?type=ATP&limit=10"

MCP server

The tennis MCP endpoint exposes 7 typed tools to LLM clients (Claude Desktop, ChatGPT, Cursor, Gemini). Drop the config below into your client and ask it questions in plain English.

POST /mcp/ JSON-RPC 2.0

Streamable HTTP transport. Auth via the same Authorization: Token header (or ?token= query param).

Available tools:

  • list_tournaments — filter by circuit/category
  • list_players — filter by gender/country
  • search_players — by name fragment
  • list_matches — by status, date window
  • get_match — match details by ID
  • get_predictions — upcoming match predictions
  • get_rankings — top N ATP or WTA

Claude Desktop config

// claude_desktop_config.json { "mcpServers": { "bzzoiro-tennis": { "url": "https://sports.bzzoiro.com/tennis/mcp/", "transport": "http", "headers": { "Authorization": "Token YOUR_TOKEN" } } } }

Examples

Today's live matches with set scores

import requests H = {"Authorization": "Token YOUR_TOKEN"} r = requests.get("https://sports.bzzoiro.com/tennis/api/v2/matches/live/", headers=H).json() for m in r: sets = m["sets_detail"] or [] score = " ".join(f"{s['p1']}-{s['p2']}" for s in sets) print(f"{m['player1']['name']} vs {m['player2']['name']} — {score}")

Predictions for an upcoming tournament

const H = { Authorization: "Token YOUR_TOKEN" }; // Get all upcoming Wimbledon matches const matches = await fetch("https://sports.bzzoiro.com/tennis/api/v2/matches/?tournament=Wimbledon&status=scheduled", { headers: H }) .then(r => r.json()); for (const m of matches.results) { console.log(m.player1.name, "vs", m.player2.name); }

Need help? Email bzzoiro@proton.me. Bug reports welcome.