{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/citoapi/main/json-schema/citoapi-tennis-match-detail-response-schema.json",
  "title": "MatchDetailResponse",
  "description": "Comprehensive match detail response including set scores and stats.\n\nServes both archived (completed) matches and matches still on the live\nboard: the canonical ``id``/``player1``/``player2``/``status``/``sets``\nvocabulary is shared by both, so a customer can write one Match type\nagainst ``/matches/{id}`` whatever state the match is in. ``winner_id``/\n``loser_id``/``winner``/``loser`` are null while a match is still in\nprogress (there is no winner yet); ``player1``/``player2`` are always\npopulated.",
  "x-generated": "2026-10-08",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/citoapi-v1-openapi.json#/components/schemas/TennisMatchDetailResponse",
  "properties": {
    "id": {
      "type": "string",
      "title": "Id",
      "description": "Unique match identifier"
    },
    "tournament_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Tournament Id",
      "description": "Tournament ID"
    },
    "tournament": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisTournamentSummaryInfo"
        },
        {
          "type": "null"
        }
      ],
      "description": "Tournament metadata"
    },
    "match_date": {
      "type": "string",
      "title": "Match Date",
      "description": "Match date (YYYY-MM-DD)"
    },
    "tour": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Tour",
      "description": "Tour: ATP or WTA",
      "default": "ATP"
    },
    "surface": {
      "type": "string",
      "title": "Surface",
      "description": "Surface"
    },
    "round": {
      "type": "string",
      "title": "Round",
      "description": "Round code"
    },
    "best_of": {
      "type": "integer",
      "title": "Best Of",
      "description": "Best of 3 or 5 sets",
      "default": 3
    },
    "score": {
      "type": "string",
      "title": "Score",
      "description": "Official score string (or the live scoreline while in progress)"
    },
    "outcome": {
      "type": "string",
      "title": "Outcome",
      "description": "Match outcome",
      "default": "COMPLETED"
    },
    "status": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Status",
      "description": "Canonical status: SCHEDULED, IN_PROGRESS, COMPLETED, RETIREMENT, ..."
    },
    "duration_minutes": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "title": "Duration Minutes",
      "description": "Duration in minutes"
    },
    "winner_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Winner Id",
      "description": "Winner ID (null while the match is in progress)"
    },
    "loser_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Loser Id",
      "description": "Loser ID (null while the match is in progress)"
    },
    "winner_sets_won": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "title": "Winner Sets Won",
      "description": "Sets won by the winner; null while the match is in progress, when there is no winner yet -- read sets[] for the running count"
    },
    "loser_sets_won": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "title": "Loser Sets Won",
      "description": "Sets won by the loser; null while the match is in progress, when there is no loser yet -- read sets[] for the running count"
    },
    "scheduled_at": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Scheduled At",
      "description": "Full scheduled/kickoff timestamp (ISO 8601), when the source provides one"
    },
    "tournament_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Tournament Name",
      "description": "Tournament name as free text; populated even when `tournament`/`tournament_id` are not yet linked (e.g. a live match not yet reconciled to a tournament id)"
    },
    "round_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Round Name",
      "description": "Human-readable round name, the same label the list routes return"
    },
    "winner": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisMatchParticipant"
        },
        {
          "type": "null"
        }
      ],
      "description": "Winner details (null while in progress)"
    },
    "loser": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisMatchParticipant"
        },
        {
          "type": "null"
        }
      ],
      "description": "Loser details (null while in progress)"
    },
    "player1": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisMatchParticipant"
        },
        {
          "type": "null"
        }
      ],
      "description": "Canonical player1 (the winner once decided; always populated for a resolved match)"
    },
    "player2": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisMatchParticipant"
        },
        {
          "type": "null"
        }
      ],
      "description": "Canonical player2 (the loser once decided; always populated for a resolved match)"
    },
    "winner_side": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "title": "Winner Side",
      "description": "Which side won: 1 (player1), 2 (player2), or null while in progress / unknown"
    },
    "sets": {
      "items": {
        "$ref": "#/$defs/TennisMatchSetItem"
      },
      "type": "array",
      "title": "Sets",
      "description": "Set-by-set box score"
    },
    "stats": {
      "anyOf": [
        {
          "$ref": "#/$defs/TennisMatchStatsSummary"
        },
        {
          "type": "null"
        }
      ],
      "description": "Match serving and return statistics"
    }
  },
  "type": "object",
  "required": [
    "id",
    "match_date",
    "surface",
    "round",
    "score"
  ],
  "$defs": {
    "TennisMatchParticipant": {
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Id",
          "description": "Player ID (null when unresolved, e.g. an unlinked doubles pair)"
        },
        "name": {
          "type": "string",
          "title": "Name",
          "description": "Player full name"
        },
        "ioc": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Ioc",
          "description": "Country IOC code"
        },
        "seed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Seed",
          "description": "Tournament seed"
        },
        "entry": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Entry",
          "description": "Entry code (e.g. Q, WC, LL, PR)"
        },
        "rank": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Rank",
          "description": "Official rank at time of match"
        },
        "is_winner": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Is Winner",
          "description": "Winner indicator"
        }
      },
      "type": "object",
      "required": [
        "name"
      ],
      "title": "MatchParticipant",
      "description": "Player participant summary in a match.\n\n``id`` is optional so this model also covers doubles pairs and live rows,\nwhere the feed has not resolved an individual player id (e.g. a combined\npair name like \"Bolelli S./Vavassori A.\" with no per-partner id)."
    },
    "TennisMatchSetItem": {
      "properties": {
        "set_number": {
          "type": "integer",
          "title": "Set Number",
          "description": "Set number (1, 2, 3, 4, 5)"
        },
        "winner_games": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Winner Games",
          "description": "Games won by match winner, once decided"
        },
        "loser_games": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Loser Games",
          "description": "Games won by match loser, once decided"
        },
        "player1_games": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Player1 Games",
          "description": "Games won by player1 (canonical, always populated)"
        },
        "player2_games": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Player2 Games",
          "description": "Games won by player2 (canonical, always populated)"
        },
        "tiebreak": {
          "anyOf": [
            {
              "$ref": "#/$defs/TennisTiebreakDetail"
            },
            {
              "type": "null"
            }
          ],
          "description": "Tiebreak points if set reached tiebreak"
        }
      },
      "type": "object",
      "required": [
        "set_number"
      ],
      "title": "MatchSetItem",
      "description": "Set-by-set box score item.\n\n``set_number`` is the canonical field name shared with the live feed\n(which otherwise calls this ``set_num``). ``player1_games``/``player2_games``\nare the canonical per-side fields, always populated; ``winner_games``/\n``loser_games`` stay for back-compat and are populated once a winner is\nknown (null while the match this set belongs to is still in progress)."
    },
    "TennisMatchStatsSummary": {
      "properties": {
        "winner": {
          "$ref": "#/$defs/TennisPlayerMatchStats"
        },
        "loser": {
          "$ref": "#/$defs/TennisPlayerMatchStats"
        }
      },
      "type": "object",
      "required": [
        "winner",
        "loser"
      ],
      "title": "MatchStatsSummary",
      "description": "Combined match statistics for winner and loser."
    },
    "TennisPlayerMatchStats": {
      "properties": {
        "aces": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Aces",
          "description": "Aces served"
        },
        "double_faults": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Double Faults",
          "description": "Double faults committed"
        },
        "serve_points": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Serve Points",
          "description": "Total service points played"
        },
        "first_serves_in": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Serves In",
          "description": "First serves in"
        },
        "first_serves_won": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Serves Won",
          "description": "First serve points won"
        },
        "second_serves_won": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Second Serves Won",
          "description": "Second serve points won"
        },
        "first_serve_pct": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Serve Pct",
          "description": "1st serve in %"
        },
        "first_serve_win_pct": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Serve Win Pct",
          "description": "1st serve points won %"
        },
        "second_serve_win_pct": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Second Serve Win Pct",
          "description": "2nd serve points won %"
        },
        "service_games_played": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Service Games Played",
          "description": "Service games played"
        },
        "break_points_saved": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Break Points Saved",
          "description": "Break points saved"
        },
        "break_points_faced": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Break Points Faced",
          "description": "Break points faced"
        },
        "break_points_converted": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Break Points Converted",
          "description": "Break points converted"
        },
        "break_point_opportunities": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Break Point Opportunities",
          "description": "Break point chances"
        },
        "total_points_won": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Total Points Won",
          "description": "Total points won"
        }
      },
      "type": "object",
      "title": "PlayerMatchStats",
      "description": "Granular match statistics for a single player."
    },
    "TennisTiebreakDetail": {
      "properties": {
        "winner_points": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Winner Points",
          "description": "Points scored by tiebreak winner"
        },
        "loser_points": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Loser Points",
          "description": "Points scored by tiebreak loser"
        }
      },
      "type": "object",
      "title": "TiebreakDetail",
      "description": "Tiebreak point breakdown."
    },
    "TennisTournamentSummaryInfo": {
      "properties": {
        "id": {
          "type": "string",
          "title": "Id",
          "description": "Tournament ID"
        },
        "name": {
          "type": "string",
          "title": "Name",
          "description": "Tournament name"
        },
        "year": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Year",
          "description": "Tournament year"
        },
        "surface": {
          "type": "string",
          "title": "Surface",
          "description": "Surface"
        },
        "level": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Level",
          "description": "Tier code"
        },
        "category": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Category",
          "description": "Canonical event category: grand_slam, masters_1000, wta_1000, tour_finals, atp_tour, wta_tour, challenger, itf, davis_cup, billie_jean_king_cup, other. ATP 250 and ATP 500 both report atp_tour because the source does not separate them"
        },
        "city": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "City",
          "description": "Host city"
        },
        "country": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Country",
          "description": "Host country code"
        }
      },
      "type": "object",
      "required": [
        "id",
        "name",
        "surface"
      ],
      "title": "TournamentSummaryInfo",
      "description": "Tournament context metadata embedded in match detail."
    }
  }
}