{
  "openapi": "3.1.0",
  "info": {
    "title": "Arena Fighter participant API",
    "version": "0.44.0",
    "description": "Discover, build, register and manage a bot. Covers public discovery/data and participant bot operations; browser account management and operator APIs are documented in the HTML/Markdown API guide. Combat is JSON over WebSocket, not an HTTP operation. Read GET /api for current authentication requirements, operational limits and downloads."
  },
  "servers": [
    {
      "url": "https://arena.victris.ai"
    }
  ],
  "externalDocs": {
    "description": "Full API, account onboarding and WebSocket guide",
    "url": "https://arena.victris.ai/guide/api"
  },
  "x-websocket": {
    "url": "wss://arena.victris.ai/bot",
    "authorization": "Authorization: Bearer <bot token>",
    "guide": "https://arena.victris.ai/docs/bot-guide",
    "schemas": "https://arena.victris.ai/docs",
    "observation_schema": "https://arena.victris.ai/docs/schema/server-observation.json",
    "turn_schema": "https://arena.victris.ai/docs/schema/bot-turn.json"
  },
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "Discover endpoints, onboarding, versions and live operational limits",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/leaderboard": {
      "get": {
        "operationId": "getLeaderboard",
        "summary": "Read bot rankings",
        "parameters": [
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LeaderboardRow"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/users/{handle}": {
      "get": {
        "operationId": "getUser",
        "summary": "Read a user's public profile and bots",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/ladders": {
      "get": {
        "operationId": "getLadders",
        "summary": "List visible ladders and an explicitly requested ladder",
        "parameters": [
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Ladder"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/events": {
      "get": {
        "operationId": "getEvents",
        "summary": "List public events and an explicitly requested event",
        "parameters": [
          {
            "name": "event",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Event"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "Read online bots, active matches, capacity and drain status",
        "parameters": [
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Omit to read status across all ladders."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/lobby": {
      "get": {
        "operationId": "getLobby",
        "summary": "Read connected bot versions and queue state",
        "parameters": [
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LobbyEntry"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/changelog": {
      "get": {
        "operationId": "getChangelog",
        "summary": "Read release history and running versions",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "versions": {
                      "$ref": "#/components/schemas/Versions"
                    },
                    "markdown": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "versions",
                    "markdown"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/bots": {
      "post": {
        "operationId": "registerBot",
        "summary": "Register an account-owned bot",
        "description": "Complete account onboarding and choose a handle first. AccountBearer accepts an account agent key or browser Supabase session, not a bot token or MCP OAuth token. OwnerKey accepts an account agent key; local anonymous ladders may also accept operator-issued legacy owner keys. The optional RegistrationKey scheme appears only when configured by this ladder. The returned bot token is shown once.",
        "parameters": [],
        "security": [
          {
            "AccountBearer": []
          },
          {
            "OwnerKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{2,24}$"
                  },
                  "owner": {
                    "type": "string",
                    "description": "Self-declared owner on explicit anonymous local ladders only."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisteredBot"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/bots/{name}": {
      "get": {
        "operationId": "getBot",
        "summary": "Read a bot's versions, ratings, health and recent matches",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{2,24}$"
            }
          },
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Bot"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteUnplayedBot",
        "summary": "Delete an owned bot that has never played",
        "description": "Requires an account agent key. A played bot cannot be deleted here; its owner can retire it through the browser account API. An already retired bot returns outcome retired without mutation.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{2,24}$"
            }
          }
        ],
        "security": [
          {
            "AgentBearer": []
          },
          {
            "OwnerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "deleted",
                        "retired"
                      ]
                    }
                  },
                  "required": [
                    "name",
                    "outcome"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/bots/{name}/ratings": {
      "get": {
        "operationId": "getBotRatings",
        "summary": "Read sampled rating history",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{2,24}$"
            }
          },
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "exclusiveMinimum": 0
            },
            "description": "Omit for all time; otherwise read the last N days."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatingHistory"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/matches": {
      "get": {
        "operationId": "getMatches",
        "summary": "Read recent matches",
        "parameters": [
          {
            "name": "ladder",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "public"
            },
            "description": "Scope to this ladder. Unknown ladders return 404."
          },
          {
            "name": "bot",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          },
          {
            "name": "stats",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "true"
              ]
            },
            "description": "Include stats, or null if unavailable."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/Match"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "stats": {
                            "type": [
                              "object",
                              "null"
                            ]
                          }
                        },
                        "required": []
                      }
                    ]
                  }
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/matches/{id}": {
      "get": {
        "operationId": "getMatch",
        "summary": "Read a match result and replay links",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Match"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/matches/{id}/stats": {
      "get": {
        "operationId": "getMatchStats",
        "summary": "Read match combat statistics",
        "description": "Returns 404 when the match is voided or its replay has been trimmed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchStats"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/me": {
      "get": {
        "operationId": "getMyBot",
        "summary": "Read the bot identified by its token",
        "parameters": [],
        "security": [
          {
            "BotBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyBot"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/me/versions": {
      "post": {
        "operationId": "addBotVersion",
        "summary": "Add a version label and optional notes",
        "parameters": [],
        "security": [
          {
            "BotBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "notes": {
                    "type": "string"
                  }
                },
                "required": [
                  "label"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Version"
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/me/versions/{label}/retire": {
      "post": {
        "operationId": "retireBotVersion",
        "summary": "Retire an old bot version from ranking",
        "parameters": [
          {
            "name": "label",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "BotBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/me/token": {
      "post": {
        "operationId": "rotateBotToken",
        "summary": "Rotate this bot's token",
        "description": "Invalidates the old token. Keep the new token secret and reconnect using it.",
        "parameters": [],
        "security": [
          {
            "BotBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "token"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/docs": {
      "get": {
        "operationId": "getDocumentationIndex",
        "summary": "Discover Markdown guides and protocol JSON schemas",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "docs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "schemas": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "docs",
                    "schemas"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/download/bots": {
      "get": {
        "operationId": "getStarterCode",
        "summary": "Discover starter files, house policies and setup commands",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "about": {
                      "type": "string"
                    },
                    "guide": {
                      "type": "string"
                    },
                    "typescript": {
                      "type": "string"
                    },
                    "python": {
                      "type": "string"
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "path": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string"
                          },
                          "about": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "path",
                          "url",
                          "about"
                        ]
                      }
                    }
                  },
                  "required": [
                    "about",
                    "guide",
                    "typescript",
                    "python",
                    "files"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request rejected; inspect error and optional code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AccountBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Account agent key or Supabase browser session for registration. DELETE /api/bots requires an agent key. Account onboarding: /guide/api#account-onboarding."
      },
      "AgentBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An account's agent key; browser sessions, bot tokens and MCP OAuth tokens are not accepted."
      },
      "OwnerKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Owner-Key",
        "description": "Account agent key. Explicit anonymous local ladders may also accept operator-issued legacy keys for registration."
      },
      "BotBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Bot token returned once by registration; distinct from account credentials."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "account_url": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "Versions": {
        "type": "object",
        "properties": {
          "release": {
            "type": "string"
          },
          "engine": {
            "type": "string"
          },
          "protocol": {
            "type": "string"
          },
          "rules": {
            "type": "string"
          },
          "rules_hash": {
            "type": "string"
          },
          "schema": {
            "type": "integer"
          },
          "commit": {
            "type": "string"
          }
        },
        "required": [
          "release",
          "engine",
          "protocol",
          "rules",
          "rules_hash",
          "schema"
        ]
      },
      "RegisteredBot": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "token": {
            "type": "string",
            "description": "Shown once. Keep secret; used as BotBearer on /api/me and /bot."
          },
          "bot_endpoint": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "token",
          "bot_endpoint",
          "note"
        ]
      },
      "Version": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "created": {
            "type": "string"
          },
          "retired": {
            "type": "boolean"
          },
          "rating": {
            "type": "integer"
          },
          "rating_deviation": {
            "type": "integer"
          },
          "leaderboard_score": {
            "type": "integer"
          },
          "wins": {
            "type": "integer"
          },
          "losses": {
            "type": "integer"
          },
          "draws": {
            "type": "integer"
          },
          "win_rate": {
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "label",
          "notes",
          "created",
          "retired",
          "rating",
          "rating_deviation",
          "leaderboard_score",
          "wins",
          "losses",
          "draws",
          "win_rate"
        ]
      },
      "LeaderboardRow": {
        "type": "object",
        "properties": {
          "rank": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "house": {
            "type": "boolean"
          },
          "online": {
            "type": "boolean"
          },
          "rating": {
            "type": "integer"
          },
          "rating_deviation": {
            "type": "integer"
          },
          "leaderboard_score": {
            "type": "integer"
          },
          "wins": {
            "type": "integer"
          },
          "losses": {
            "type": "integer"
          },
          "draws": {
            "type": "integer"
          }
        },
        "required": [
          "rank",
          "name",
          "display_name",
          "version",
          "owner",
          "house",
          "online",
          "rating",
          "rating_deviation",
          "leaderboard_score",
          "wins",
          "losses",
          "draws"
        ]
      },
      "Match": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "ladder_id": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "seed": {
            "type": "integer"
          },
          "map": {
            "type": "string"
          },
          "started": {
            "type": "string"
          },
          "ended": {
            "type": "string"
          },
          "duration_ms": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Measured wall-clock milliseconds from match setup until the result is ready to persist, including startup and replay saving. Null for older matches."
          },
          "final_tick": {
            "type": "integer"
          },
          "reason": {
            "type": "string"
          },
          "winner": {
            "type": [
              "string",
              "null"
            ]
          },
          "voided": {
            "type": "boolean"
          },
          "bots": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "version": {
                  "type": "string"
                },
                "house": {
                  "type": "boolean"
                },
                "avatar": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "rating_before": {
                  "type": "number"
                },
                "rating_after": {
                  "type": "number"
                }
              },
              "required": [
                "id",
                "name",
                "display_name",
                "version",
                "house",
                "avatar"
              ]
            }
          },
          "replay_url": {
            "type": "string"
          },
          "stats_url": {
            "type": "string"
          },
          "watch_url": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "ladder_id",
          "mode",
          "seed",
          "map",
          "ended",
          "duration_ms",
          "final_tick",
          "reason",
          "winner",
          "voided",
          "bots",
          "replay_url",
          "stats_url",
          "watch_url"
        ]
      },
      "Bot": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "owner_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "house": {
            "type": "boolean"
          },
          "online": {
            "type": "boolean"
          },
          "created": {
            "type": "string"
          },
          "avatar": {
            "type": [
              "string",
              "null"
            ]
          },
          "ladder_id": {
            "type": "string"
          },
          "online_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "qualifying_games": {
            "type": "integer"
          },
          "versions": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Version"
                },
                {
                  "type": "object",
                  "properties": {
                    "rank": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "health": {
                      "type": [
                        "object",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "rank",
                    "health"
                  ]
                }
              ]
            }
          },
          "recent_matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            }
          }
        },
        "required": [
          "name",
          "display_name",
          "owner",
          "owner_url",
          "house",
          "online",
          "created",
          "avatar",
          "ladder_id",
          "online_version",
          "qualifying_games",
          "versions",
          "recent_matches"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "handle": {
            "type": "string"
          },
          "created": {
            "type": "string"
          },
          "ladder_id": {
            "type": "string"
          },
          "bots": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "owner": {
                  "type": "string"
                },
                "owner_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "house": {
                  "type": "boolean"
                },
                "online": {
                  "type": "boolean"
                },
                "created": {
                  "type": "string"
                },
                "avatar": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "retired": {
                  "type": "boolean"
                },
                "version": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "rank": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "leaderboard_score": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "rating": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "rating_deviation": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "wins": {
                  "type": "integer"
                },
                "losses": {
                  "type": "integer"
                },
                "draws": {
                  "type": "integer"
                }
              },
              "required": [
                "name",
                "display_name",
                "owner",
                "owner_url",
                "house",
                "online",
                "created",
                "avatar",
                "retired",
                "version",
                "rank",
                "leaderboard_score",
                "rating",
                "rating_deviation",
                "wins",
                "losses",
                "draws"
              ]
            }
          }
        },
        "required": [
          "handle",
          "created",
          "ladder_id",
          "bots"
        ]
      },
      "MyBot": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "owner_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "house": {
            "type": "boolean"
          },
          "online": {
            "type": "boolean"
          },
          "created": {
            "type": "string"
          },
          "avatar": {
            "type": [
              "string",
              "null"
            ]
          },
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Version"
            }
          }
        },
        "required": [
          "name",
          "display_name",
          "owner",
          "owner_url",
          "house",
          "online",
          "created",
          "avatar",
          "versions"
        ]
      },
      "RatingHistory": {
        "type": "object",
        "properties": {
          "since": {
            "type": [
              "string",
              "null"
            ]
          },
          "games": {
            "type": "integer"
          },
          "points": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "match_id": {
                  "type": "string"
                },
                "ended": {
                  "type": "string"
                },
                "version": {
                  "type": "string"
                },
                "rating": {
                  "type": "integer"
                },
                "delta": {
                  "type": "integer"
                },
                "result": {
                  "type": "string",
                  "enum": [
                    "W",
                    "L",
                    "D"
                  ]
                },
                "opponent": {
                  "type": "string"
                },
                "opponent_display_name": {
                  "type": "string"
                },
                "map": {
                  "type": "string"
                }
              },
              "required": [
                "match_id",
                "ended",
                "version",
                "rating",
                "delta",
                "result",
                "opponent",
                "opponent_display_name",
                "map"
              ]
            }
          }
        },
        "required": [
          "since",
          "games",
          "points"
        ]
      },
      "Ladder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "visible": {
            "type": "boolean"
          },
          "access": {
            "type": "string"
          },
          "phase": {
            "type": "string",
            "enum": [
              "upcoming",
              "open",
              "closed"
            ]
          },
          "leaderboard_url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ]
            }
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "enabled",
          "visible",
          "access",
          "phase",
          "leaderboard_url",
          "events"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "ladder_id": {
            "type": "string"
          },
          "ladder": {
            "$ref": "#/components/schemas/Ladder"
          },
          "opens_at": {
            "type": "string"
          },
          "closes_at": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "phase": {
            "type": "string",
            "enum": [
              "upcoming",
              "open",
              "closed"
            ]
          },
          "ready": {
            "type": "boolean"
          },
          "achievements": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "condition": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "condition"
              ]
            }
          },
          "opponents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                }
              },
              "required": [
                "kind",
                "name",
                "display_name"
              ]
            }
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "ladder_id",
          "ladder",
          "opens_at",
          "closes_at",
          "timezone",
          "enabled",
          "phase",
          "ready",
          "achievements",
          "opponents"
        ]
      },
      "ApiIndex": {
        "type": "object",
        "properties": {
          "bot_endpoint": {
            "type": "string"
          },
          "authentication_required": {
            "type": "boolean"
          },
          "mcp": {
            "type": [
              "string",
              "null"
            ]
          },
          "openapi": {
            "type": "string"
          },
          "llms_txt": {
            "type": "string"
          },
          "docs": {
            "type": "string"
          },
          "bot_code": {
            "type": "string"
          },
          "versions": {
            "$ref": "#/components/schemas/Versions"
          },
          "onboarding": {
            "type": "object",
            "properties": {
              "account_url": {
                "type": "string"
              },
              "signup_url": {
                "type": "string"
              },
              "guide_url": {
                "type": "string"
              },
              "signup_endpoint": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "token_endpoint": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "handle_endpoint": {
                "type": "string"
              },
              "registration_endpoint": {
                "type": "string"
              },
              "claim_endpoint": {
                "type": "string"
              }
            },
            "required": [
              "account_url",
              "signup_url",
              "guide_url",
              "signup_endpoint",
              "token_endpoint",
              "handle_endpoint",
              "registration_endpoint",
              "claim_endpoint"
            ]
          },
          "operational_policy": {
            "type": "object"
          },
          "simulator": {
            "type": "object",
            "properties": {
              "javascript": {
                "type": "string"
              },
              "script": {
                "type": "string"
              },
              "python": {
                "type": "string"
              },
              "docs": {
                "type": "string"
              }
            },
            "required": [
              "javascript",
              "script",
              "python",
              "docs"
            ]
          },
          "maps": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "bot_endpoint",
          "authentication_required",
          "mcp",
          "openapi",
          "llms_txt",
          "docs",
          "bot_code",
          "versions",
          "onboarding",
          "operational_policy",
          "simulator",
          "maps",
          "endpoints"
        ]
      },
      "MatchStats": {
        "$ref": "#/components/schemas/MatchStats/definitions/match-stats",
        "definitions": {
          "match-stats": {
            "type": "object",
            "properties": {
              "stats_version": {
                "type": "integer",
                "description": "bumped whenever a field changes meaning"
              },
              "map": {
                "type": "string"
              },
              "seed": {
                "type": "integer"
              },
              "ticks": {
                "type": "integer",
                "description": "ticks resolved"
              },
              "winner": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "fighter id of the winner, or null for a draw"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "how the match ended"
              },
              "fighters": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer",
                      "description": "fighter id, as in hello.bot_id"
                    },
                    "name": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "hp": {
                      "type": "integer",
                      "description": "hp at the end of the match"
                    },
                    "alive": {
                      "type": "boolean"
                    },
                    "moves": {
                      "type": "integer",
                      "description": "one-tile steps taken"
                    },
                    "moves_blocked": {
                      "type": "integer",
                      "description": "accepted steps that didn't happen because another fighter was in the way"
                    },
                    "dashes": {
                      "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                    },
                    "dash_tiles": {
                      "type": "integer",
                      "description": "tiles covered by dashing"
                    },
                    "weapons": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "object",
                        "properties": {
                          "uses": {
                            "type": "integer",
                            "description": "attacks fired: sent and accepted by the engine"
                          },
                          "hits": {
                            "type": "integer",
                            "description": "hits on an opponent"
                          },
                          "damage": {
                            "type": "integer",
                            "description": "hp those hits removed, the power buff included"
                          }
                        },
                        "required": [
                          "uses",
                          "hits",
                          "damage"
                        ],
                        "additionalProperties": false
                      },
                      "description": "by attack name; every attack in the rules is listed. Accuracy is hits / uses"
                    },
                    "ricochets": {
                      "type": "object",
                      "properties": {
                        "bounces": {
                          "type": "integer",
                          "description": "shots that bounced off a wall"
                        },
                        "hits": {
                          "type": "integer",
                          "description": "hits scored after a bounce (also counted in weapons)"
                        },
                        "damage": {
                          "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                        }
                      },
                      "required": [
                        "bounces",
                        "hits",
                        "damage"
                      ],
                      "additionalProperties": false
                    },
                    "pickups": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "pickups taken, by kind; every kind in the rules is listed"
                    },
                    "healed": {
                      "type": "integer",
                      "description": "hp restored by health pickups"
                    },
                    "damage_dealt": {
                      "type": "integer",
                      "description": "hp removed from opponents"
                    },
                    "dealt_by_source": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "damage_dealt by source: attack names, \"wall_slam\", \"collision\""
                    },
                    "damage_taken": {
                      "type": "integer",
                      "description": "hp lost"
                    },
                    "taken_by_source": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "damage_taken by source: attack names, \"wall_slam\", \"collision\", \"zone\""
                    },
                    "wall_slams": {
                      "type": "integer",
                      "description": "opponents this fighter's repulsor slammed into a wall"
                    },
                    "knocked_back": {
                      "type": "integer",
                      "description": "times this fighter was shoved"
                    },
                    "stunned": {
                      "type": "integer",
                      "description": "times this fighter was stunned"
                    },
                    "zone_ticks": {
                      "type": "integer",
                      "description": "ticks ended outside the safe zone"
                    },
                    "rejected": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "parts of turns the engine refused, by reason"
                    },
                    "refused_turns": {
                      "type": "integer",
                      "description": "turns with at least one refused part"
                    },
                    "refused_turns_by_reason": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "turns with a refused part, by reason; a turn counts once per reason"
                    },
                    "server_idles": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                      },
                      "description": "ticks the server played as idle for this fighter, by reason (timeout, malformed_json, disconnected…)"
                    },
                    "timing": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {
                            "replies": {
                              "type": "integer",
                              "description": "timed replies, timeouts included (a reply that never came counts at the deadline)"
                            },
                            "mean_ms": {
                              "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                            },
                            "p50_ms": {
                              "type": "integer",
                              "description": "median reply; added up over several matches, the upper bound of its histogram bucket"
                            },
                            "p95_ms": {
                              "type": "integer",
                              "description": "95th percentile reply; added up over several matches, the upper bound of its histogram bucket"
                            },
                            "max_ms": {
                              "type": "integer",
                              "description": "slowest reply"
                            },
                            "near_limit": {
                              "type": "integer",
                              "description": "replies that took at least 80% of the tick limit: one slow moment from a timeout"
                            },
                            "tick_ms": {
                              "type": "integer",
                              "description": "the per-tick limit the replies were timed against"
                            },
                            "budget_ms": {
                              "type": "integer",
                              "description": "the match's total response-time budget"
                            },
                            "budget_ms_left": {
                              "type": "integer",
                              "description": "budget left at the end of the match (the lowest, added up over several)"
                            },
                            "histogram": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/MatchStats/definitions/match-stats/properties/seed"
                              },
                              "description": "replies per bucket: upper bounds 10, 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 850, 900, 950, 1000 thousandths of tick_ms, then slower"
                            }
                          },
                          "required": [
                            "replies",
                            "mean_ms",
                            "p50_ms",
                            "p95_ms",
                            "max_ms",
                            "near_limit",
                            "tick_ms",
                            "budget_ms",
                            "budget_ms_left",
                            "histogram"
                          ],
                          "additionalProperties": false,
                          "description": "how long the bot took to reply, as the server timed it: from sending the observation to the reply arriving, network included"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "reply times; null when nothing was timed (the simulator doesn't time replies)"
                    },
                    "disconnects": {
                      "type": "integer",
                      "description": "contiguous runs of recorded disconnected idle turns for this fighter, not socket-close events"
                    },
                    "disqualified": {
                      "type": "boolean",
                      "description": "the match ended because this fighter failed too many ticks in a row"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "version",
                    "hp",
                    "alive",
                    "moves",
                    "moves_blocked",
                    "dashes",
                    "dash_tiles",
                    "weapons",
                    "ricochets",
                    "pickups",
                    "healed",
                    "damage_dealt",
                    "dealt_by_source",
                    "damage_taken",
                    "taken_by_source",
                    "wall_slams",
                    "knocked_back",
                    "stunned",
                    "zone_ticks",
                    "rejected",
                    "refused_turns",
                    "refused_turns_by_reason",
                    "server_idles",
                    "timing",
                    "disconnects",
                    "disqualified"
                  ],
                  "additionalProperties": false
                }
              },
              "match_id": {
                "type": "string"
              }
            },
            "required": [
              "stats_version",
              "map",
              "seed",
              "ticks",
              "winner",
              "reason",
              "fighters",
              "match_id"
            ],
            "additionalProperties": false,
            "description": "what each fighter did over one match"
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "online": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "bot": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                }
              },
              "required": [
                "bot",
                "display_name",
                "state"
              ]
            }
          },
          "active_matches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "ladder_id": {
                  "type": "string"
                },
                "mode": {
                  "type": "string"
                },
                "map": {
                  "type": "string"
                },
                "tick": {
                  "type": "integer"
                },
                "bots": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "display_names": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "ladder_id",
                "mode",
                "map",
                "tick",
                "bots",
                "display_names"
              ]
            }
          },
          "capacity": {
            "type": "object",
            "properties": {
              "running": {
                "type": "integer"
              },
              "max": {
                "type": "integer"
              }
            },
            "required": [
              "running",
              "max"
            ]
          },
          "draining": {
            "type": "boolean"
          }
        },
        "required": [
          "online",
          "active_matches",
          "capacity",
          "draining"
        ]
      },
      "LobbyEntry": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "version": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": "string"
          },
          "house": {
            "type": "boolean"
          },
          "avatar": {
            "type": [
              "string",
              "null"
            ]
          },
          "rating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "rating_deviation": {
            "type": [
              "integer",
              "null"
            ]
          },
          "leaderboard_score": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Score for the connected version: rating minus twice the greater of its standard error and 25, rounded once; null before queueing."
          }
        },
        "required": [
          "name",
          "display_name",
          "state",
          "house",
          "avatar"
        ]
      }
    }
  }
}