Leaderboards endpoints

Season leaderboards built from match statistics.

GET/tennis/leaderboards/1st-serve-won

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/aces

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/break-conversion

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/break-points-saved

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/comeback-wins

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/deciding-set-record

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/finals-record

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/return-games-won

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}
GET/tennis/leaderboards/tiebreak-win-pct

Season 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.

ParameterInTypeDescription
seasonqueryintegermin 1968 · max 2030 · default 2026
tourquerystring
limitqueryintegermin 1 · max 100 · default 20
bash
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.

json
{
  "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
}