Tennis API: Free ATP and WTA Scores, Rankings and Match Stats
Neither tour publishes a public API. We called their sites and the free routes on 2 November 2026.
Last updated:
Is There a Public Tennis API?
No. Neither the ATP nor the WTA publishes a public API, developer docs or a free key. On 2 November 2026, atptour.com answered our script with HTTP 403 on every page we tried. The WTA's own JSON answered, but the WTA terms forbid automated access to its sites, so we treat it as closed. Both tours limit their sites to personal, non-commercial use.
Free tennis data comes from three places that answered plain requests with no key.
| Route | What it gives | Key needed |
|---|---|---|
| ESPN tennis endpoints | Matches, set scores, seeds, top 150 rankings | No |
| theScore tennis endpoints | Matches, serve stats, top 500 rankings | No |
| Match Charting Project | Shot-by-shot CSV files | No |
| Licensed data providers | Official feeds with a contract and an SLA | Yes: sports data APIs |
What the ATP and WTA Sites Answered
Each call below went out with curl's default headers on 2 November 2026, with no cookie and no token.
| URL | Status | What came back |
|---|---|---|
https://www.atptour.com/en/scores/current | 403 | A Cloudflare block page (5,660 bytes). The homepage and terms page got the same, with or without a browser User-Agent |
https://app.atptour.com/api/v2/gateway/livematches/website?scoringTournamentLevel=tour | 403 | The same block page |
https://api.wtatennis.com/tennis/tournaments/?page=0&pageSize=10&excludeLevels=ITF&from=2026-11-01&to=2026-11-03 | 200 | JSON with 10 tournaments, among them "Chennai Open - Chennai, IND" with level "WTA 250" and status "inProgress" |
atptour.com blocked us before it served a page, so we could not see which JSON it loads. The gateway URL comes from open-source scrapers on GitHub, which send a copied browser User-Agent, Referer and Origin. We sent none of them. The WTA's scores page names api.wtatennis.com/tennis as its data host, and its script makes the tournaments call above first. That call answered, but the WTA terms rule out automated access, so this page documents no WTA endpoint.
ESPN Tennis Scoreboard and Rankings
https://site.api.espn.com/apis/site/v2/sports/tennis/atp/scoreboard
https://site.api.espn.com/apis/site/v2/sports/tennis/wta/scoreboard
Our ESPN API page covers the host and its other sports. In tennis, each item in events is a tournament, and the matches sit two levels down. Our ATP call on 2 November 2026 returned the Rolex Paris Masters (13-2026) in 201 KB: 76 Men's Singles matches from qualifying to the final, and 27 doubles matches. The WTA call returned five tournaments.
| Field | Type | What it holds |
|---|---|---|
events[].name | string | Tournament name: "Rolex Paris Masters" |
events[].groupings[].grouping.displayName | string | The draw: "Men's Singles", "Men's Doubles" |
groupings[].competitions[] | array | The matches in that draw |
competitions[].round.displayName | string | "Qualifying Final", "Round 1", "Quarterfinal" |
competitions[].status.type.description | string | "Scheduled", "Final", "Retired" or "Canceled" |
competitors[].athlete.displayName | string | The player in singles; "TBD" until the draw fills |
competitors[].roster.displayName | string | The pair in doubles: "Quentin Halys / Pierre-Hugues Herbert" |
competitors[].linescores[] | array | One row per set: value (games) and tiebreak (that player's tiebreak points) |
competitors[].curatedRank.current | integer | The seed. It matched the seed in notes on every Wimbledon 2026 singles match |
competitions[].notes[0].text | string | The result line, on finished matches only |
Competitors carry no score field, and statistics was an empty array on every match, so the scoreboard has no aces or serve numbers. Match 186466 on Court Central has status "Retired" and this note: "Karen Khachanov (RUS) bt Denis Shapovalov (CAN) 6-3 6-7 (6-8) 1-4 ret". In doubles, a match tiebreak appears as a third set of 1-0 with tiebreak 10.
Dates
?dates=YYYYMMDD returns every tournament in play that day, with all of its matches, so filter on competitions[].date yourself. ?dates=20261101 gave Vienna, Basel and Paris. ?dates=20260712 gave Wimbledon with 239 men's singles matches, qualifying included, in a 2.1 MB response. A month (?dates=202607) returned eight tournaments. A range returned 200 here, unlike the team sports, but ?dates=20260701-20260712 held three tournaments and left out Wimbledon, which started on 22 June.
Rankings
/apis/site/v2/sports/tennis/atp/rankings and .../wta/rankings each returned the top 150 with current, previous, points and trend, dated 29 October 2026. The ATP top three were Alexander Zverev, Jannik Sinner and Carlos Alcaraz, the same as theScore's list.
import requests
url = 'https://site.api.espn.com/apis/site/v2/sports/tennis/atp/scoreboard'
data = requests.get(url, timeout=10).json()
for event in data['events']:
for group in event.get('groupings', []):
for match in group['competitions']:
if match['status']['type']['completed'] and match.get('notes'):
print(event['name'], '|', match['round']['displayName'], '|', match['notes'][0]['text'])
Run on 2 November 2026, it printed 37 finished matches. The first: "Rolex Paris Masters | Qualifying 1st Round | Mattia Bellucci (ITA) bt Pablo Carreno Busta (ESP) 6-1 7-6 (7-3)".
theScore Tennis Endpoints
theScore's app API on api.thescore.com answers tennis under atp and wta. Its events/current returned one tournament object for each tour, not a list of matches: the Rolex Paris Masters (10460, ground_type "hardcourt_indoor", event_status "in_progress") and the Hong Kong Tennis Open (10543). The other tournaments are in schedule.
| Endpoint | What it returns | Example |
|---|---|---|
/atp/events/current | One tournament object | name "Rolex Paris Masters" |
/atp/schedule | Each month with its event_ids | November 2026: 10457, 10490, 10460, 10488, 10504 |
/atp/events/{id}/matches | The tournament's matches | 50 singles matches for 10460 |
/atp/matches/{id} | One match with stats for each player | team_1_stats.aces 14 for 171500 |
/atp/standings | The rankings, 500 rows | place 1, points 9550 |
The tournament object links to no matches, but /events/{id}/matches answered when we called it: 50 singles matches for Paris and no doubles, with or without ?rpp=200. Each match gives games per set in team_1_scores and team_2_scores: [7, 6, 6] against [6, 7, 3] for Ugo Humbert over Botic Van de Zandschulp. The single-match call adds aces, double faults, break points (Humbert won 4 of 7) and total points won (115). For sportsbook prices on the same matches, read our sports odds API guide.
theScore's terms grant a personal, non-commercial licence and ban spiders and robots, and api.thescore.com/robots.txt disallows every path. Our theScore API page quotes the clauses.
Historical Tennis Data
Jeff Sackmann's tennis_atp and tennis_wta repositories held match results and rankings as CSV files. On 2 November 2026 both returned HTTP 404 on GitHub's site, its API and the raw file URLs, and his profile listed one public repository.
That repository is the Match Charting Project: shot-by-shot records of pro matches, charted by volunteers. Its match files listed 7,566 men's and 4,264 women's matches, from the 1960 Roland Garros final to September 2026. The points files hold one row per point, with the score, the server and the coded shots. The licence is CC BY-NC-SA 4.0, so you credit the project and keep use non-commercial. Our free sports datasets page lists open data for other sports.
Status Codes You Will See
403 Forbidden
atptour.com and app.atptour.com returned the Cloudflare block page as HTML, not JSON. We did not try to get past it.
400 Bad Request
ESPN's summary?event=, the game endpoint on our ESPN page, does not work for tennis. It returned 400 for a match id (186466), a tournament id (13-2026) and a made-up id. A bad date (?dates=20261399) and an unknown league (tennis/itf/scoreboard) both returned {"code":400,"message":"Failed to get events endpoint."}.
404 Not Found
theScore returned JSON with "reason":"Not Found" for /atp/events/99999999 and for its /matches path.
200 with no matches
ESPN's WTA scoreboard listed the American Tennis Open Miami with an empty groupings array and no status or venue key. Code that reads event['status'] without a default fails on it.
Tour Terms and Limitations
What the tour terms say
Section 7 of the ATP terms: "You may use the Website and/or Content solely for your own individual non-commercial, entertainment and informational purposes." And: "Systematic retrieval of data or other Content from the Website, including but not limited to scores, statistics, and/or rankings, whether to create or compile, directly or indirectly, a collection, compilation, database, or directory, is prohibited absent prior express written permission from ATP." The WTA Terms of Use (last updated April 6, 2020) say you must not "use automated means to access the WTA Sites".
- No published rate limit: ESPN sent
cache-control: max-age=10on the ATP scoreboard and no rate-limit headers. theScore sent none either. Cache what you fetch. - Non-commercial only: theScore's licence and the Match Charting Project's licence both rule out commercial use.
- Unofficial routes can change: ESPN and theScore document none of these endpoints and can move them without notice.
When your app takes bets, sells a product or needs official ATP or WTA data, compare licensed providers on sports data APIs or in the directory.
Community Resources
- tennis_MatchChartingProject on GitHub: the CSV files, a data dictionary and the charting spreadsheet (fetched November 2026).
- Public-ESPN-API tennis reference on GitHub: a community list of ESPN's tennis paths. We tested only the ones on this page.
We found no maintained Python wrapper for ESPN's tennis endpoints.
Frequently Asked Questions
api.wtatennis.com, and a tournaments call there answered HTTP 200 to plain curl. But the WTA publishes no docs or key, and its Terms of Use forbid automated access to the WTA Sites, so treat it as closed.https://site.api.espn.com/apis/site/v2/sports/tennis/atp/scoreboard (or wta) and walk events[].groupings[].competitions[]. Each match has status.type.description, the players in competitors and the games per set in competitors[].linescores. ESPN set a 10-second cache window on the ATP response.cache-control window on the ATP scoreboard, and theScore sent none. Cache what you fetch and poll no faster than your app needs.Need Official Tennis Data?
The free routes cover hobby projects and models. A production app needs a contract, an SLA and support. Compare licensed providers in our directory.