Leaderboards endpoints
Season leaderboards built from match statistics.
- /tennis/leaderboards/1st-serve-won · Season First-Serve-Won Leaderboard
- /tennis/leaderboards/aces · Season Aces Leaderboard
- /tennis/leaderboards/break-conversion · Season Break-Conversion Leaderboard
- /tennis/leaderboards/break-points-saved · Season Break-Points-Saved Leaderboard
- /tennis/leaderboards/comeback-wins · Season Comeback-Wins Leaderboard
- /tennis/leaderboards/deciding-set-record · Season Deciding-Set-Record Leaderboard
- /tennis/leaderboards/finals-record · Season Finals-Record Leaderboard
- /tennis/leaderboards/return-games-won · Season Return-Games-Won Leaderboard
- /tennis/leaderboards/tiebreak-win-pct · Season Tiebreak-Win-Pct Leaderboard
/tennis/leaderboards/1st-serve-wonSeason First-Serve-Won Leaderboard
Share of first-serve points won per player, summed over winner and loser sides of real match_stats rows joined to matches in the season. Only players with at least 300 first serves in qualify.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/1st-serve-won"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "first_serve_won",
"minimum_attempts": 300,
"items": [
{
"player_id": "atp_126774",
"full_name": "Stefanos Tsitsipas",
"first_serve_points_won": 1363,
"first_serves_in": 1657,
"matches": 35,
"pct": 82.3,
"id": "atp_126774",
"name": "Stefanos Tsitsipas"
},
{
"player_id": "atp_200303",
"full_name": "Pavel Kotov",
"first_serve_points_won": 1232,
"first_serves_in": 1517,
"matches": 35,
"pct": 81.2,
"id": "atp_200303",
"name": "Pavel Kotov"
}
],
"total": 20
}/tennis/leaderboards/acesSeason Aces Leaderboard
Season ace totals per player, summed over winner and loser sides of real match_stats rows joined to matches in the season. No defaults, no estimates: a player with no stat rows simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/aces"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "aces",
"items": [
{
"player_id": "atp_102093",
"full_name": "Martin Damm",
"aces": 485,
"matches": 38,
"id": "atp_102093",
"name": "Martin Damm"
},
{
"player_id": "atp_209951",
"full_name": "Petr Bar Biryukov",
"aces": 457,
"matches": 44,
"id": "atp_209951",
"name": "Petr Bar Biryukov"
}
],
"total": 20
}/tennis/leaderboards/break-conversionSeason Break-Conversion Leaderboard
Share of break opportunities converted per player, from real match_stats rows joined to matches in the season. Breaks are the exact return-side mirror of the stored serve-side columns: a winner converts (loser faced minus loser saved), a loser converts (winner faced minus winner saved), over the corresponding faced total. Only players with at least 50 break opportunities qualify (ATP 2026: 1089 eligible, tops 54.9-60.4). No defaults, no estimates: a player with no stat rows simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/break-conversion"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "break_conversion",
"minimum_attempts": 50,
"items": [
{
"player_id": "wta_221377",
"full_name": "Fabienne Gettwart",
"break_points_won": 40,
"break_opportunities": 57,
"matches": 6,
"pct": 70.2,
"id": "wta_221377",
"name": "Fabienne Gettwart"
},
{
"player_id": "wta_221396",
"full_name": "Victoria Mulville",
"break_points_won": 39,
"break_opportunities": 61,
"matches": 8,
"pct": 63.9,
"id": "wta_221396",
"name": "Victoria Mulville"
}
],
"total": 20
}/tennis/leaderboards/break-points-savedSeason Break-Points-Saved Leaderboard
Share of break points saved per player, summed over winner and loser sides of real match_stats rows joined to matches in the season. Only players facing at least 50 break points qualify.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/break-points-saved"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "break_points_saved",
"minimum_attempts": 50,
"items": [
{
"player_id": "wta_223323",
"full_name": "Barbora Palicova",
"break_points_saved": 116,
"break_points_faced": 118,
"matches": 21,
"pct": 98.3,
"id": "wta_223323",
"name": "Barbora Palicova"
},
{
"player_id": "wta_266376",
"full_name": "Mia Pohankova",
"break_points_saved": 139,
"break_points_faced": 150,
"matches": 26,
"pct": 92.7,
"id": "wta_266376",
"name": "Mia Pohankova"
}
],
"total": 20
}/tennis/leaderboards/comeback-winsSeason Comeback-Wins Leaderboard
Share of matches won after losing the first set, from real match_sets rows (set_num=1) joined to matches in the season. Set rows are stored from the match winner side, so the winner lost the opener exactly when winner_games < loser_games on the set-1 row (verified 5/5 against score_raw first sets); the match winner took that comeback by definition, so winner sides count won when the opener went against them and loser sides always count lost -- no inference, no estimates. Only COMPLETED matches count: a retirement or walkover after set 1 is not a comeback. Only players with first-set data on at least 20 matches qualify (ATP 2026: 594 eligible; WTA 2026: 210 eligible; tops ~27.6 at ship time). A player with no set-1 rows simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/comeback-wins"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "comeback_wins",
"minimum_attempts": 20,
"items": [
{
"player_id": "wta_220429",
"full_name": "Elena Milovanovic",
"comebacks_won": 12,
"matches_with_first_set": 44,
"matches": 44,
"pct": 27.3,
"id": "wta_220429",
"name": "Elena Milovanovic"
},
{
"player_id": "wta_202468",
"full_name": "Jessica Pegula",
"comebacks_won": 10,
"matches_with_first_set": 38,
"matches": 38,
"pct": 26.3,
"id": "wta_202468",
"name": "Jessica Pegula"
}
],
"total": 20
}/tennis/leaderboards/deciding-set-recordSeason Deciding-Set-Record Leaderboard
Share of deciding sets won per player, from real matches rows in the season. A match reaches a decider exactly when winner_sets_won plus loser_sets_won equals best_of (a Bo3 going the full 3 sets, a Bo5 going the full 5); the match winner won that decider by definition, so winner sides count won and loser sides count lost -- no set-level inference, no estimates. best_of=1 exhibition rows are excluded: this board rates full-format pressure play. Only players contesting at least 10 deciders qualify (ATP 2026: 291 eligible; WTA 2026: 64 eligible; both tours top 90.0 at ship time). A player with no deciders simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/deciding-set-record"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "deciding_set_record",
"minimum_attempts": 10,
"items": [
{
"player_id": "wta_236972",
"full_name": "Luisina Giovannini",
"deciders_won": 11,
"deciders_played": 11,
"matches": 11,
"pct": 100,
"id": "wta_236972",
"name": "Luisina Giovannini"
},
{
"player_id": "wta_221354",
"full_name": "Lisa Pigato",
"deciders_won": 12,
"deciders_played": 13,
"matches": 13,
"pct": 92.3,
"id": "wta_221354",
"name": "Lisa Pigato"
}
],
"total": 20
}/tennis/leaderboards/finals-recordSeason Finals-Record Leaderboard
Share of finals won per player, from real matches rows in the season. A final is exactly round='F' (the only final code in the store -- a FINAL-like round probe returns zero other variants); the match winner lifted the title by definition, so winner sides count won and loser sides count lost -- no inference, no estimates. Only COMPLETED finals count: a retirement or walkover is not a title. Only players contesting at least 3 finals qualify (ATP 2026: 66 eligible; WTA 2026: 31 eligible at ship time). A player with no finals simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/finals-record"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "finals_record",
"minimum_attempts": 3,
"items": [
{
"player_id": "atp_209407",
"full_name": "Max Basing",
"finals_won": 3,
"finals_played": 3,
"matches": 3,
"pct": 100,
"id": "atp_209407",
"name": "Max Basing"
},
{
"player_id": "atp_209952",
"full_name": "Sean Cuenin",
"finals_won": 5,
"finals_played": 5,
"matches": 5,
"pct": 100,
"id": "atp_209952",
"name": "Sean Cuenin"
}
],
"total": 20
}/tennis/leaderboards/return-games-wonSeason Return-Games-Won Leaderboard
Share of return games won per player, from real match_stats rows joined to matches in the season. Return games won are breaks achieved -- the exact return-side mirror of the stored serve-side columns: a winner breaks (loser faced minus loser saved), a loser breaks (winner faced minus winner saved) -- over the opponent's service games played (loser/winner sv_gms). sv_gms semantics are verified, not assumed: over 234,635 tiebreak-free matches, winner+loser sv_gms equals total set games in 98.05%; over 96,174 tiebreak matches it equals total minus tiebreak sets in 97.0% (tiebreaks are not service games, the correct tour convention); derived breaks fit within sv_gms in 99.5% of 330,922 fully-populated rows; Alcaraz ATP 2026 comes out 31.3%, the realistic tour-level band. Only players with at least 100 return games played qualify (ATP 2026: 987 eligible, top 51.5; WTA 2026: 567 eligible, top 64.0). Rows missing any of the three opponent-side inputs are excluded, never defaulted. No estimates: a player with no stat rows simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/return-games-won"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "return_games_won",
"minimum_attempts": 100,
"items": [
{
"player_id": "wta_269717",
"full_name": "Neus Torner Sensano",
"return_games_won": 71,
"return_games_played": 111,
"matches": 13,
"pct": 64,
"id": "wta_269717",
"name": "Neus Torner Sensano"
},
{
"player_id": "wta_260168",
"full_name": "Alexandra Shubladze",
"return_games_won": 200,
"return_games_played": 336,
"matches": 36,
"pct": 59.5,
"id": "wta_260168",
"name": "Alexandra Shubladze"
}
],
"total": 20
}/tennis/leaderboards/tiebreak-win-pctSeason Tiebreak-Win-Pct Leaderboard
Share of tiebreaks won per player, from real match_sets rows joined to matches in the season. Set rows are stored from the match winner side, so a tiebreak goes to the winner side when winner_games > loser_games and to the loser side otherwise; a 7-6 set without tiebreak point columns counts the same way (the /h2h tiebreak_record predicate). Super tiebreaks (10-point match tiebreaks) are excluded: this board rates classic 7-point tiebreak play. Only players contesting at least 10 tiebreaks qualify (ATP 2026: 361 eligible; WTA 2026: 13 eligible). No defaults, no estimates: a player with no tiebreak sets simply does not appear.
| Parameter | In | Type | Description |
|---|---|---|---|
| season | query | integer | min 1968 · max 2030 · default 2026 |
| tour | query | string | |
| limit | query | integer | min 1 · max 100 · default 20 |
curl -H "x-api-key: YOUR_API_KEY" \
"https://api.citoapi.com/api/v1/tennis/leaderboards/tiebreak-win-pct"Real response (HTTP 200), captured from the production API; long arrays cut to two items.
{
"success": true,
"season": 2026,
"tour": null,
"stat": "tiebreak_win_pct",
"minimum_attempts": 10,
"items": [
{
"player_id": "wta_211756",
"full_name": "Patcharin Cheapchandej",
"tiebreaks_won": 10,
"tiebreaks_played": 11,
"matches": 11,
"pct": 90.9,
"id": "wta_211756",
"name": "Patcharin Cheapchandej"
},
{
"player_id": "atp_211628",
"full_name": "Koki Matsuda",
"tiebreaks_won": 15,
"tiebreaks_played": 17,
"matches": 15,
"pct": 88.2,
"id": "atp_211628",
"name": "Koki Matsuda"
}
],
"total": 20
}