{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/bigballsdata-com/json-schema/bigballsdata-com-match-schema.json",
  "title": "Match",
  "description": "The match object. This one shape is returned by `/v1/matches`, `/v1/stored/matches` and `/v1/cricket/matches` alike, for every sport (verified field-for-field across all three on 2026-09-18).",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/bigballsdata-com-api-openapi.json#/components/schemas/Match",
  "type": "object",
  "required": [
    "id",
    "sport",
    "league",
    "kickoff_utc",
    "status",
    "home",
    "away"
  ],
  "properties": {
    "id": {
      "$ref": "#/$defs/StoredId"
    },
    "sport": {
      "$ref": "#/$defs/Sport"
    },
    "league": {
      "type": "string",
      "description": "The league's DISPLAY name as served here (e.g. \"MLB\", \"NHL\"). This is not the `?league=` code; see LeagueCode for that."
    },
    "kickoff_utc": {
      "type": "string",
      "format": "date-time"
    },
    "status": {
      "$ref": "#/$defs/MatchStatus"
    },
    "home": {
      "$ref": "#/$defs/MatchSide"
    },
    "away": {
      "$ref": "#/$defs/MatchSide"
    },
    "score": {
      "oneOf": [
        {
          "$ref": "#/$defs/MatchScore"
        },
        {
          "type": "null"
        }
      ]
    },
    "linescore": {
      "oneOf": [
        {
          "$ref": "#/$defs/Linescore"
        },
        {
          "type": "null"
        }
      ]
    },
    "attendance": {
      "type": [
        "integer",
        "null"
      ]
    },
    "broadcast": {
      "type": [
        "string",
        "null"
      ]
    },
    "has_odds": {
      "type": "boolean",
      "description": "Whether stored odds exist for this match; see /v1/matches/{id}/odds."
    },
    "round": {
      "type": [
        "string",
        "null"
      ],
      "description": "Competition segment as the source names it, e.g. \"Regular Season - 2\" or \"Group Stage\". This is the axis to group gameweek analytics by: a postponed fixture keeps its round while its kickoff_utc moves by weeks, so bucketing by date splits one gameweek and merges another. Free text rather than an integer, because the phase carries meaning an integer would discard. Null where the source supplies none, currently populated for soccer only."
    },
    "season": {
      "type": "string",
      "description": "NOT EMITTED by the list endpoints as measured on 2026-09-18. Declared because callers may hold it from older payloads; branch on its absence rather than expecting it."
    },
    "venue": {
      "type": "string",
      "description": "NOT EMITTED by the list endpoints as measured on 2026-09-18."
    },
    "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "NOT EMITTED by the list endpoints as measured on 2026-09-18."
    }
  },
  "$defs": {
    "Linescore": {
      "type": "object",
      "description": "Per-period totals. The array length and meaning follow the sport, and are not uniform even within one sport, so read it positionally only after checking `sport`.",
      "properties": {
        "home": {
          "type": "array",
          "items": {
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "away": {
          "type": "array",
          "items": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      }
    },
    "MatchScore": {
      "type": "object",
      "description": "Final or current goal/run/point totals. Null on a match with no score yet.",
      "required": [
        "home",
        "away"
      ],
      "properties": {
        "home": {
          "type": [
            "integer",
            "null"
          ]
        },
        "away": {
          "type": [
            "integer",
            "null"
          ]
        }
      }
    },
    "MatchSide": {
      "type": "object",
      "description": "One side of a match. The field names are `id`/`name`; there is no `team_id`/`team_name` here. Until 2026-09-18 this schema said `team_id` + `team_name`, which no endpoint has ever returned.",
      "required": [
        "id",
        "name"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/StoredId"
        },
        "name": {
          "type": "string",
          "maxLength": 120
        },
        "short_name": {
          "type": [
            "string",
            "null"
          ],
          "maxLength": 40
        },
        "logo_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Served from our own asset endpoint; treat it as opaque and do not construct it."
        }
      }
    },
    "MatchStatus": {
      "type": "string",
      "enum": [
        "scheduled",
        "live",
        "in_progress",
        "finished",
        "postponed",
        "cancelled",
        "suspended"
      ]
    },
    "Sport": {
      "type": "string",
      "enum": [
        "football",
        "basketball",
        "baseball",
        "ice_hockey",
        "cricket",
        "mma",
        "boxing",
        "formula1",
        "american_football"
      ]
    },
    "StoredId": {
      "type": "string",
      "format": "uuid",
      "description": "A stored BigBalls id. This is the identifier every match, team, player and league endpoint returns, and the one every `{id}` path segment accepts. Take it from the `id` field of the corresponding list endpoint and use it as-is."
    }
  }
}