{
  "openapi": "3.1.0",
  "info": {
    "title": "Bikeball Matchday API",
    "version": "1.0.0",
    "summary": "Read-only results of published cycle-ball (Radball) tournaments.",
    "description": "Tournaments that organizers made public in Bikeball Matchday (bikeball.app/matchday): schedule, scores, goals and cards per team, standings and final ranking, live during the match day and afterwards. Team-level data only — player names, birth dates, UCI IDs and card reasons are never included. No authentication. Responses may be up to a few seconds old; clocks are computed at request time. Please credit bikeball.app as the source. The same data is available to AI assistants via the MCP server at https://bikeball.app/mcp (tools find_tournaments, get_tournament, get_live_score)."
  },
  "servers": [
    {
      "url": "https://bikeball.app/api/v1/matchday"
    }
  ],
  "paths": {
    "/live": {
      "get": {
        "operationId": "getLiveAll",
        "summary": "All tournaments being played right now",
        "description": "Every published tournament with a match in progress, or with matches played today and more to come: per court the current match with score and clock, the next and the last match. Used by bikeball.app/matchday/live.",
        "responses": {
          "200": {
            "description": "Live tournaments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiveAll"
                }
              }
            }
          }
        }
      }
    },
    "/tournaments": {
      "get": {
        "operationId": "listTournaments",
        "summary": "List published tournaments",
        "description": "Live tournaments first, then by date, newest first.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "planned",
                "live",
                "finished"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Words to find in name, location, venue or age class.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Earliest date (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Latest date (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tournaments",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tournaments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TournamentSummary"
                      }
                    },
                    "attribution": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/tournaments/{id}": {
      "get": {
        "operationId": "getTournament",
        "summary": "One tournament with schedule, results and standings",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "Tournament",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tournament"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/tournaments/{id}/live": {
      "get": {
        "operationId": "getLive",
        "summary": "What is happening on each court right now",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "name": "court",
            "in": "query",
            "description": "Only this court.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 6
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Live state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Live"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Id": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Tournament id (12 characters).",
        "schema": {
          "type": "string",
          "pattern": "^[A-HJ-NP-Z2-9]{12}$"
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "TournamentSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "start": {
            "type": [
              "string",
              "null"
            ],
            "description": "Planned start, local time HH:MM."
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "venue": {
            "type": [
              "string",
              "null"
            ]
          },
          "class": {
            "type": [
              "string",
              "null"
            ],
            "description": "Age class, e.g. Elite, U15."
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "live",
              "finished"
            ]
          },
          "teams": {
            "type": "integer"
          },
          "matches": {
            "type": "integer"
          },
          "played": {
            "type": "integer"
          },
          "courts": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "timeZone": {
            "type": "string",
            "description": "IANA time zone of the venue."
          },
          "teamNames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Team names (up to 24), for searching by club."
          },
          "podium": {
            "type": [
              "array",
              "null"
            ],
            "description": "Ranks 1–3 with team names once the tournament is finished; null while it runs or without an overall ranking.",
            "items": {
              "type": "object",
              "properties": {
                "rank": {
                  "type": "integer"
                },
                "team": {
                  "type": "string"
                }
              }
            }
          },
          "stream": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Live stream link given by the organizer (http/https), shown on bikeball.app as \"Live stream available\"."
          }
        }
      },
      "Tournament": {
        "type": "object",
        "properties": {
          "schema": {
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "tournament": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "date": {
                "type": "string",
                "format": "date"
              },
              "start": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "timeZone": {
                "type": "string",
                "description": "IANA time zone of the venue."
              },
              "location": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "venue": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "class": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "classId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "association": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "season": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "mode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "courts": {
                "type": "integer"
              },
              "halfTimeMinutes": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "planned",
                  "live",
                  "finished"
                ]
              },
              "matchesTotal": {
                "type": "integer"
              },
              "matchesPlayed": {
                "type": "integer"
              },
              "stream": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri",
                "description": "Live stream link given by the organizer (http/https), shown on bikeball.app as \"Live stream available\"."
              }
            }
          },
          "teams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Team"
            }
          },
          "phases": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "type": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            }
          },
          "standings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Standing"
            }
          },
          "finalRanking": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "rank": {
                  "type": "integer"
                },
                "team": {
                  "type": "string"
                }
              }
            }
          },
          "attribution": {
            "type": "string"
          },
          "links": {
            "type": "object",
            "properties": {
              "self": {
                "type": "string"
              },
              "live": {
                "type": "string"
              }
            }
          },
          "asOf": {
            "type": "string",
            "format": "date-time",
            "description": "When clocks were computed. A running clock has remainingMs less by the time elapsed since asOf."
          }
        }
      },
      "Team": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "short": {
            "type": [
              "string",
              "null"
            ]
          },
          "club": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Match": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "number": {
            "type": "integer",
            "description": "Position in the order of the day."
          },
          "time": {
            "type": [
              "string",
              "null"
            ],
            "description": "Local time at the venue, HH:MM — actual start if played, else expected."
          },
          "start": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "UTC."
          },
          "end": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "UTC."
          },
          "court": {
            "type": "integer"
          },
          "phase": {
            "type": [
              "string",
              "null"
            ]
          },
          "group": {
            "type": [
              "string",
              "null"
            ],
            "description": "A, B, … in group phases."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "E.g. Finale, Halbfinale 1."
          },
          "home": {
            "type": [
              "string",
              "null"
            ],
            "description": "Team id."
          },
          "away": {
            "type": [
              "string",
              "null"
            ],
            "description": "Team id."
          },
          "homeLabel": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who it will be, while the team is not known yet."
          },
          "awayLabel": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "called",
              "running",
              "halftime",
              "shootout",
              "ended",
              "final"
            ]
          },
          "score": {
            "$ref": "#/components/schemas/Score",
            "description": "The result that counts — for a forfeit the awarded 0:5 (or more, if the opponent already led by more)."
          },
          "halfTime": {
            "$ref": "#/components/schemas/Score"
          },
          "extraTime": {
            "type": "boolean"
          },
          "shootout": {
            "$ref": "#/components/schemas/Score"
          },
          "winner": {
            "type": [
              "string",
              "null"
            ],
            "description": "Team id."
          },
          "forfeit": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "home",
              "away",
              null
            ],
            "description": "Side the match was awarded against (0:5)."
          },
          "referee": {
            "type": [
              "string",
              "null"
            ],
            "description": "Team id of the refereeing team."
          },
          "clock": {
            "type": [
              "object",
              "null"
            ],
            "description": "Only while the match is in progress.",
            "properties": {
              "running": {
                "type": "boolean"
              },
              "half": {
                "type": [
                  "integer",
                  "string"
                ],
                "description": "1, 2 or \"extra\"."
              },
              "remainingMs": {
                "type": "integer"
              },
              "remaining": {
                "type": "string",
                "description": "m:ss"
              },
              "elapsedMs": {
                "type": "integer"
              }
            }
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "goal",
                    "yellow",
                    "yellowRed",
                    "red"
                  ]
                },
                "team": {
                  "type": "string",
                  "description": "Team id credited with the goal or shown the card."
                },
                "minute": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "half": {
                  "type": "integer",
                  "description": "1, 2 or 3 (extra time)."
                },
                "ownGoal": {
                  "type": "boolean"
                }
              }
            }
          },
          "playedScore": {
            "$ref": "#/components/schemas/Score",
            "description": "Score as played, only when the match was awarded after it had started."
          },
          "forfeitReason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "noShow",
              "awarded",
              null
            ],
            "description": "noShow: team did not appear; awarded: decided at the table, e.g. after a red card."
          }
        }
      },
      "Score": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "home": {
            "type": "integer"
          },
          "away": {
            "type": "integer"
          }
        }
      },
      "Standing": {
        "type": "object",
        "properties": {
          "phase": {
            "type": "string"
          },
          "phaseName": {
            "type": [
              "string",
              "null"
            ]
          },
          "group": {
            "type": [
              "string",
              "null"
            ]
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rank": {
                  "type": "integer"
                },
                "team": {
                  "type": "string"
                },
                "tied": {
                  "type": "boolean"
                },
                "played": {
                  "type": "integer"
                },
                "won": {
                  "type": "integer"
                },
                "drawn": {
                  "type": "integer"
                },
                "lost": {
                  "type": "integer"
                },
                "goalsFor": {
                  "type": "integer"
                },
                "goalsAgainst": {
                  "type": "integer"
                },
                "goalDiff": {
                  "type": "integer"
                },
                "points": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Live": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "timeZone": {
            "type": "string"
          },
          "teams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Team"
            }
          },
          "courts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "court": {
                  "type": "integer"
                },
                "current": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Match"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "next": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Match"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "last": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Match"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          },
          "attribution": {
            "type": "string"
          },
          "asOf": {
            "type": "string",
            "format": "date-time",
            "description": "When clocks were computed. A running clock has remainingMs less by the time elapsed since asOf."
          }
        }
      },
      "LiveAll": {
        "type": "object",
        "properties": {
          "asOf": {
            "type": "string",
            "format": "date-time"
          },
          "tournaments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "start": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "location": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "venue": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "class": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "timeZone": {
                  "type": "string"
                },
                "teams": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Team"
                  }
                },
                "phases": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                },
                "matches": {
                  "type": "integer"
                },
                "played": {
                  "type": "integer"
                },
                "updated": {
                  "type": "string",
                  "format": "date-time"
                },
                "courts": {
                  "$ref": "#/components/schemas/Live/properties/courts"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "stream": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uri",
                  "description": "Live stream link given by the organizer (http/https), shown on bikeball.app as \"Live stream available\"."
                }
              }
            }
          },
          "attribution": {
            "type": "string"
          }
        }
      }
    }
  }
}
