{ "openapi": "3.1.0", "info": { "title": "TeamBattles API", "version": "0.3.0", "description": "Public developer API for TeamBattles. Authenticate with an API key: Authorization: Bearer tb_." }, "servers": [ { "url": "https://teambattles.gg/api/v1", "description": "Production" } ], "tags": [ { "name": "Games", "description": "Public game catalog and playlists.", "x-group": "Public Read API" }, { "name": "Players", "description": "Public player profiles, stats, connections, affiliations, and trophies.", "x-group": "Public Read API" }, { "name": "Teams", "description": "Public team profiles and rosters.", "x-group": "Public Read API" }, { "name": "Organizations", "description": "Public organization profiles, members, teams, stats, and discovery.", "x-group": "Public Read API" }, { "name": "Leaderboards", "description": "Player, team, and organization leaderboards and rank lookups.", "x-group": "Public Read API" }, { "name": "Match Discovery", "description": "Open-match discovery and read-only match detail, players, and scores.", "x-group": "Public Read API" }, { "name": "League Discovery", "description": "Public league discovery, profiles, standings, seasons, rules, and eligibility.", "x-group": "Public Read API" }, { "name": "Tournament Discovery", "description": "Public tournament discovery and read-only tournament detail, bracket, participants, and free agents.", "x-group": "Public Read API" }, { "name": "My Account", "description": "The API key owner's own connections and game ranks.", "x-group": "Personal API" }, { "name": "My Matches", "description": "The key owner's matches and captain match writes (create, accept, ready, scores, lifecycle).", "x-group": "Personal API" }, { "name": "My Teams", "description": "The key owner's team writes: create, edit, disband, manage members, roles, and captaincy.", "x-group": "Personal API" }, { "name": "My Organizations", "description": "The key owner's organization writes: create, edit, delete, manage members, roles, and ownership.", "x-group": "Personal API" }, { "name": "My Tournaments", "description": "The key owner's tournaments and personal tournament calendar.", "x-group": "Personal API" }, { "name": "Match Chat", "description": "Read, send, and report messages in a match chat room.", "x-group": "Personal API" }, { "name": "Game: Matches", "description": "Game-developer match lifecycle: create, read, status, and forfeit.", "x-group": "Game Developer API" }, { "name": "Game: Scores", "description": "Game-developer score submission: single, per-map, and batch.", "x-group": "Game Developer API" }, { "name": "Game: Rosters & Stats", "description": "Game-developer roster reads and player-stat submission.", "x-group": "Game Developer API" }, { "name": "League: Membership & Teams", "description": "League staff membership, team applications, and ownership transfer.", "x-group": "League Admin API" }, { "name": "League: Announcements", "description": "League admin announcement posts to league members.", "x-group": "League Admin API" }, { "name": "League: Seasons", "description": "League season lifecycle: create, activate, complete, delete.", "x-group": "League Admin API" }, { "name": "League: Rules & Config", "description": "League rules, points, display rules, branding, settings, games, and shutdown.", "x-group": "League Admin API" }, { "name": "League: Scores", "description": "League admin match score and player-stat submission and status.", "x-group": "League Admin API" }, { "name": "League: Moderation", "description": "League bans, penalties, and cooldowns.", "x-group": "League Admin API" }, { "name": "League: Tickets", "description": "League support-ticket workflow.", "x-group": "League Admin API" }, { "name": "League: Overview", "description": "League admin dashboards and activity feed.", "x-group": "League Admin API" }, { "name": "Tournament: Lifecycle", "description": "Tournament creation, settings, approval submission, registration windows, round scheduling, cancellation, start, and match regeneration.", "x-group": "Tournament Organizer API" }, { "name": "Tournament: Registration", "description": "Organizer application review, participant removal and disqualification, and organizer roster edits.", "x-group": "Tournament Organizer API" }, { "name": "Tournament: Bracket & Results", "description": "Organizer bracket result overrides and reverts.", "x-group": "Tournament Organizer API" }, { "name": "Tournament: Free Agents", "description": "Organizer moderation of the tournament free-agent pool.", "x-group": "Tournament Organizer API" }, { "name": "Tournament: Staff & Invites", "description": "Tournament staff management and organizer team invites.", "x-group": "Tournament Organizer API" }, { "name": "Tournament Entry", "description": "Competitor entry, applications, withdrawal, check-in, roster edits, invite responses, and the caller's own tournament standing.", "x-group": "Tournament Competitor API" }, { "name": "Tournament Free Agency", "description": "Competitor free-agent pool listings and pickup offers.", "x-group": "Tournament Competitor API" }, { "name": "Webhooks", "description": "Webhook endpoint management, test, secret rotation, and delivery replay.", "x-group": "Webhooks" }, { "name": "Strategies", "description": "Read shared strategy boards and shapes by slug.", "x-group": "Platform Tools" }, { "name": "Streaming", "description": "Live-stream status lookups.", "x-group": "Platform Tools" }, { "name": "Twitch", "description": "Twitch chat badge proxies.", "x-group": "Platform Tools" }, { "name": "Uploads", "description": "Image upload URL minting.", "x-group": "Platform Tools" }, { "name": "Support", "description": "The key owner's support tickets and replies.", "x-group": "Platform Tools" } ], "x-tagGroups": [ { "name": "Public Read API", "tags": [ "Games", "Players", "Teams", "Organizations", "Leaderboards", "Match Discovery", "League Discovery", "Tournament Discovery" ] }, { "name": "Personal API", "tags": [ "My Account", "My Matches", "My Teams", "My Organizations", "My Tournaments", "Match Chat" ] }, { "name": "Game Developer API", "tags": [ "Game: Matches", "Game: Scores", "Game: Rosters & Stats" ] }, { "name": "League Admin API", "tags": [ "League: Membership & Teams", "League: Announcements", "League: Seasons", "League: Rules & Config", "League: Scores", "League: Moderation", "League: Tickets", "League: Overview" ] }, { "name": "Tournament Organizer API", "tags": [ "Tournament: Lifecycle", "Tournament: Registration", "Tournament: Bracket & Results", "Tournament: Free Agents", "Tournament: Staff & Invites" ] }, { "name": "Tournament Competitor API", "tags": [ "Tournament Entry", "Tournament Free Agency" ] }, { "name": "Webhooks", "tags": [ "Webhooks" ] }, { "name": "Platform Tools", "tags": [ "Strategies", "Streaming", "Twitch", "Uploads", "Support" ] } ], "paths": { "/chat/messages/{messageId}/report": { "post": { "operationId": "reportChatMessage", "tags": [ "Match Chat" ], "summary": "Report a chat message", "description": "Reports a chat message for staff moderation as the API key owner. The owner must be a participant of the message's chat room; a non-participant receives 403. System messages and the owner's own messages cannot be reported. Reporting the same message twice is idempotent (returns the existing report with alreadyReported: true). Requires the chat.write scope and the writes feature. Supports the Idempotency-Key header.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "messageId", "schema": { "type": "string", "description": "ID of the chat message to report." }, "required": true, "description": "ID of the chat message to report." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportChatMessageRequestBody" } } } }, "responses": { "200": { "description": "The message was reported (or was already reported).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportChatMessageResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches": { "post": { "operationId": "listGameMatches", "tags": [ "Game: Matches" ], "summary": "List matches for the developer's approved game", "description": "Returns matches for the API key owner's approved (bound) game, with legacy cursor pagination. Requires the game.lifecycle:read permission.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListGameMatchesBody" } } } }, "responses": { "200": { "description": "Legacy cursor-paginated result. pagination.cursor is null when there are no more pages.", "content": { "application/json": { "schema": { "type": "object", "properties": { "matches": { "type": "array", "items": { "$ref": "#/components/schemas/GameMatch" } }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "pagination": { "type": "object", "properties": { "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hasMore": { "type": "boolean" } }, "required": [ "cursor", "hasMore" ], "additionalProperties": false }, "timestamp": { "type": "string" } }, "required": [ "matches", "count", "pagination", "timestamp" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}": { "get": { "operationId": "getGameMatch", "tags": [ "Game: Matches" ], "summary": "Get a single match's details", "description": "Returns detailed info for one match, validated to belong to the API key owner's approved game. Requires the game.lifecycle:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "The requested match plus a response timestamp.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameMatchDetailResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/forfeit": { "post": { "operationId": "forfeitGameMatch", "tags": [ "Game: Matches" ], "summary": "Forfeit a match on behalf of one participating team", "description": "Forfeits the match for the supplied team; the other participating team wins. Valid only while the match is ACCEPTED, READY, or IN_PROGRESS. Requires the game.lifecycle:read-write permission and a key bound to the match's game. Supports an optional `Idempotency-Key` request header: a retry with the same key and body replays the original response, while the same key with a different body returns 409 error_idempotency_key_conflict.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameForfeitBody" } } } }, "responses": { "200": { "description": "The match was forfeited successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameForfeitResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/player-stats": { "post": { "operationId": "submitGamePlayerStats", "tags": [ "Game: Rosters & Stats" ], "summary": "Submit or update player stats for a map", "description": "Sets per-player stats on an existing map score for the given mapIndex. Requires the game.scores:write permission. Supports an optional `Idempotency-Key` request header: a retry with the same key and body replays the original response, while the same key with a different body returns 409 error_idempotency_key_conflict. The idempotency identity is scoped per match.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GamePlayerStatsBody" } } } }, "responses": { "200": { "description": "The player stats were updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GamePlayerStatsResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/rosters": { "get": { "operationId": "getGameMatchRosters", "tags": [ "Game: Rosters & Stats" ], "summary": "Get a match's team rosters", "description": "Returns the creator and accepted team rosters for a match, validated to belong to the API key owner's approved game. Requires the game.lifecycle:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "Team rosters grouped by creator and accepted team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameMatchRostersResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/scores": { "get": { "operationId": "getGameScores", "tags": [ "Game: Scores" ], "summary": "Read all map scores for a match", "description": "Returns every recorded map score plus the aggregate series tally. Requires the game.scores:write OR game.lifecycle:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "All map scores plus the aggregate series tally.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameScoresResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "submitGameScores", "tags": [ "Game: Scores" ], "summary": "Submit map scores in a batch", "description": "Submits scores for one or more maps; game-developer scores are auto-confirmed. Requires the game.scores:write permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchScoresBody" } } } }, "responses": { "200": { "description": "Per-map submission results. success is true only when every map was confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchScoresResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/scores/{mapIndex}": { "post": { "operationId": "submitGameMapScore", "tags": [ "Game: Scores" ], "summary": "Submit a single map's score", "description": "Submits the score for one map (mapIndex from the path); game-developer scores are auto-confirmed. Requires the game.scores:write permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." }, { "in": "path", "name": "mapIndex", "schema": { "type": "string", "description": "Zero-based index of the map within the series." }, "required": true, "description": "Zero-based index of the map within the series." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameSingleMapScoreBody" } } } }, "responses": { "200": { "description": "The map score was submitted and confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameSingleMapScoreResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/{matchId}/status": { "patch": { "operationId": "updateGameMatchStatus", "tags": [ "Game: Matches" ], "summary": "Update a match's lifecycle status", "description": "Transitions a match between lifecycle states (validated against allowed transitions). Requires the game.lifecycle:read-write permission. Supports an optional `Idempotency-Key` request header that deduplicates concurrent duplicate submissions: while one request is in flight, a second request with the same key and body resolves to the same outcome, and the same key with a different body returns 409 error_idempotency_key_conflict. The idempotency identity is scoped per match and per target status. Note that this endpoint validates the live match state first, so a sequential retry sent after the transition has already succeeded returns the normal transition error (error_match_not_in_valid_state) - the live state no longer permits the transition - rather than a replayed success.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameStatusUpdateBody" } } } }, "responses": { "200": { "description": "The match status was transitioned successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameStatusUpdateResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/batch-scores": { "post": { "operationId": "submitGameBatchMatchScores", "tags": [ "Game: Scores" ], "summary": "Submit map scores across multiple matches in one call", "description": "Submits map scores for up to 50 (match, map) items in a single request. Each item is independently scope-checked against the key's bound game; an off-scope or otherwise failing item is rejected in its per-item envelope (status \"failed\", error = bare error_* code) WITHOUT failing the whole request. The response is ALWAYS HTTP 200 - inspect per-item status. Requires the game.scores:write permission. Score submission is naturally idempotent: an unconfirmed map is overwritten on re-submit and an already-confirmed map returns a per-item error_score_already_submitted_by_game, so a retried batch is safe without an Idempotency-Key.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchMatchScoresBody" } } } }, "responses": { "200": { "description": "Per-item submission results. success is true only when every item was confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchMatchScoresResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/game/matches/create": { "post": { "operationId": "createGameMatch", "tags": [ "Game: Matches" ], "summary": "Create a two-sided game-originated match", "description": "Creates an ACCEPTED + PUBLISHED match for the API key's bound game between two active teams in that game. Requires the game.lifecycle:read-write permission. Supply an optional `Idempotency-Key` request header to make retries safe: an identical key + body replays the original response, while the same key with a different body returns 409 error_idempotency_key_conflict.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameCreateMatchBody" } } } }, "responses": { "200": { "description": "The created match's ID.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameCreateMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/games": { "get": { "operationId": "listGames", "tags": [ "Games" ], "summary": "List public game catalog entries", "description": "Returns the static public game catalog and objective definitions. Requires a valid API key, but no additional permission scope.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "Public game catalog.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiGameCatalogResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/games/{id}/playlists": { "get": { "operationId": "listGamePlaylists", "tags": [ "Games" ], "summary": "List playlists for a game", "description": "Returns playlists from the static public game definition for the requested game ID. Playlist IDs are game-scoped, so shared slugs such as standard are not resolved globally.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Static public game ID/slug." }, "required": true, "description": "Static public game ID/slug." } ], "responses": { "200": { "description": "Public game playlist list.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiGamePlaylistsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/organizations": { "get": { "operationId": "listOrganizationLeaderboard", "tags": [ "Leaderboards" ], "summary": "List organization leaderboard", "description": "Returns active, public, non-disabled organizations ranked from active, enabled, non-private team stats. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } }, { "in": "query", "name": "limit", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }, { "in": "query", "name": "gameSlug", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Organization leaderboard.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrganizationLeaderboardResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/organizations/{identifier}/rank": { "get": { "operationId": "getOrganizationLeaderboardRank", "tags": [ "Leaderboards" ], "summary": "Get an organization's leaderboard rank", "description": "Returns an organization's 1-based rank for the requested leaderboard filters, or null when the organization is unranked (no qualifying match activity for the filter). Resolve the org by slug or Convex organization ID. sortBy defaults to wins (also winRate, experience). Pass gameSlug to rank by that game's stats only; omit it for the global all-games rank. Organization stats are aggregated from the org's active, enabled, non-private teams. Ranking counts only public, active, non-disabled organizations with at least one match. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." }, { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } }, { "in": "query", "name": "gameSlug", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Organization rank.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaderboardRankResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/players": { "get": { "operationId": "listPlayerLeaderboard", "tags": [ "Leaderboards" ], "summary": "List player leaderboard", "description": "Returns the global player leaderboard. gameSlug is rejected because player stats are global. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } }, { "in": "query", "name": "limit", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } } ], "responses": { "200": { "description": "Player leaderboard.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlayerLeaderboardResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/players/me/rank": { "get": { "operationId": "getPlayerLeaderboardRank", "tags": [ "Leaderboards" ], "summary": "Get the API key owner's player rank", "description": "Returns the API key owner's own rank in the global player leaderboard (the principal is ranked, so there is no identifier path param, unlike the team and organization rank endpoints). Sort with sortBy (wins, winRate, or experience; default wins). rank is null when the owner has no completed matches, has a private profile, is currently banned, or ranks beyond the bounded best-effort scan window (about 2000 entries). gameSlug is not supported and returns 400. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } } ], "responses": { "200": { "description": "Player rank.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaderboardRankResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/teams": { "get": { "operationId": "listTeamLeaderboard", "tags": [ "Leaderboards" ], "summary": "List team leaderboard", "description": "Returns active, non-disabled, non-private teams ranked by the requested stat. Requires teams.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } }, { "in": "query", "name": "limit", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }, { "in": "query", "name": "gameSlug", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Team leaderboard.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamLeaderboardResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leaderboards/teams/{identifier}/rank": { "get": { "operationId": "getTeamLeaderboardRank", "tags": [ "Leaderboards" ], "summary": "Get a team's leaderboard rank", "description": "Resolves a single team by slug or ID and returns its 1-indexed rank on the public team leaderboard. `sortBy` selects the ranking field: wins (default), winRate, or experience. Pass `gameSlug` to rank within one game's leaderboard; omit it for the global (all-games) board. An unknown `gameSlug` returns 404. `rank` is null when the team is excluded from the leaderboard (private or disabled) and also when the team ranks beyond the internal scan window, since the rank is a bounded best-effort computation rather than a full-table sort. A missing or inactive team returns 404; an active but excluded team returns 200 with rank null. Requires teams.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." }, { "in": "query", "name": "sortBy", "schema": { "$ref": "#/components/schemas/LeaderboardSortBy" } }, { "in": "query", "name": "gameSlug", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Team rank.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaderboardRankResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues": { "post": { "operationId": "discoverLeagues", "tags": [ "League Discovery" ], "summary": "Discover public leagues", "description": "Returns a paginated list of public leagues with optional search and game filtering. Requires the leagues.league_public:read permission.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DiscoverLeaguesRequestBody" } } } }, "responses": { "200": { "description": "Legacy offset-paginated result (page/limit based).", "content": { "application/json": { "schema": { "type": "object", "properties": { "leagues": { "type": "array", "items": { "$ref": "#/components/schemas/LeagueSummary" } }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "pagination": { "type": "object", "properties": { "page": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "limit": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "totalPages": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "page", "limit", "total", "totalPages" ], "additionalProperties": false }, "timestamp": { "type": "string" } }, "required": [ "leagues", "count", "pagination", "timestamp" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}": { "post": { "operationId": "getLeagueProfile", "tags": [ "League Discovery" ], "summary": "Get a league profile", "description": "Returns the public profile for a single league, resolved by slug or Convex ID. Requires the leagues.league_public:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "responses": { "200": { "description": "The league profile.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueProfileResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/activity-feed": { "post": { "operationId": "getLeagueActivityFeed", "tags": [ "League: Overview" ], "summary": "Get league activity feed", "description": "Returns recent league activity entries. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.league_admin:read access on the key. These admin reads no longer require a paid developer plan; they stay authority-gated (current league ADMIN) and rate-limited by the league owner's plan. League API WRITE routes still require the leagueOperatorApi feature (api_pro or higher) on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueActivityFeedRequestBody" } } } }, "responses": { "200": { "description": "League activity feed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueActivityFeedResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/announcements": { "post": { "operationId": "announceLeague", "tags": [ "League: Announcements" ], "summary": "Send a league announcement", "description": "Sends an announcement to all members of the league. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league announcements capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnounceLeagueRequestBody" } } } }, "responses": { "200": { "description": "The announcement was sent.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnounceLeagueResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/apply-eligibility": { "post": { "operationId": "getLeagueApplyEligibility", "tags": [ "League Discovery" ], "summary": "Get league application eligibility", "description": "Returns apply-to-join eligibility for the API key owner's applicable teams, or for a specified team the owner leads. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueApplyEligibilityRequestBody" } } } }, "responses": { "200": { "description": "League application eligibility.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueApplyEligibility" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/bans": { "post": { "operationId": "getLeagueBans", "tags": [ "League: Moderation" ], "summary": "Get league team bans", "description": "Returns team bans for a league resolved by slug, with optional status filtering. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path (or TeamBattles staff), with leagues.league_admin:read access on the key. These admin reads no longer require a paid developer plan; they stay authority-gated (current league ADMIN) and rate-limited by the league owner's plan. League API WRITE routes still require the leagueOperatorApi feature (api_pro or higher) on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BansRequestBody" } } } }, "responses": { "200": { "description": "Team bans for the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueBans" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/bans/{banId}/revoke": { "post": { "operationId": "revokeLeagueBan", "tags": [ "League: Moderation" ], "summary": "Revoke a league team ban", "description": "Revokes an active league team ban. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league bans capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "banId", "schema": { "type": "string", "description": "League ban ID." }, "required": true, "description": "League ban ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RevokeBanRequestBody" } } } }, "responses": { "200": { "description": "The league ban was revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RevokeBanResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/bans/create": { "post": { "operationId": "createLeagueBan", "tags": [ "League: Moderation" ], "summary": "Create a league team ban", "description": "Bans a team from the league and removes it from active/pending league participation. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league bans capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBanRequestBody" } } } }, "responses": { "200": { "description": "The league ban was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBanResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/branding/update": { "post": { "operationId": "updateLeagueBranding", "tags": [ "League: Rules & Config" ], "summary": "Update league branding", "description": "Updates league public profile branding and metadata. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league branding capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueBrandingRequestBody" } } } }, "responses": { "200": { "description": "The league branding was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueBrandingResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/cooldowns/{cooldownId}/clear": { "post": { "operationId": "clearLeagueCooldown", "tags": [ "League: Moderation" ], "summary": "Clear a league cooldown", "description": "Clears an active league member cooldown early. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league cooldowns capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "cooldownId", "schema": { "type": "string", "description": "League member cooldown ID." }, "required": true, "description": "League member cooldown ID." } ], "responses": { "200": { "description": "The league cooldown was cleared.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClearCooldownResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/cooldowns/config/update": { "post": { "operationId": "updateLeagueCooldownConfig", "tags": [ "League: Rules & Config" ], "summary": "Update league cooldown config", "description": "Updates the league member cooldown configuration. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league rules capability enabled on the key (league-wide cooldown policy is a config-admin write, deliberately separated from the per-member cooldowns capability). League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueCooldownConfigRequestBody" } } } }, "responses": { "200": { "description": "The league cooldown config was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueCooldownConfigResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/cooldowns/issue": { "post": { "operationId": "issueLeagueCooldown", "tags": [ "League: Moderation" ], "summary": "Issue a league cooldown", "description": "Issues or updates a manual cooldown for a league member. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league cooldowns capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueCooldownRequestBody" } } } }, "responses": { "200": { "description": "The league cooldown was issued.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueCooldownResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/dashboard/stats": { "post": { "operationId": "getLeagueDashboardStats", "tags": [ "League: Overview" ], "summary": "Get league dashboard stats", "description": "Returns aggregate league admin dashboard counts. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.league_admin:read access on the key. These admin reads no longer require a paid developer plan; they stay authority-gated (current league ADMIN) and rate-limited by the league owner's plan. League API WRITE routes still require the leagueOperatorApi feature (api_pro or higher) on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "responses": { "200": { "description": "League dashboard stats.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueDashboardStatsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/display-rules": { "post": { "operationId": "getLeagueDisplayRules", "tags": [ "League Discovery" ], "summary": "Get league display rules", "description": "Returns display rules configured for a league game. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueDisplayRulesRequestBody" } } } }, "responses": { "200": { "description": "League display rules.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueDisplayRules" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/display-rules/{displayRuleId}": { "delete": { "operationId": "removeLeagueDisplayRule", "tags": [ "League: Rules & Config" ], "summary": "Remove a league display rule", "description": "Removes an informational display rule. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league display_rules capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "displayRuleId", "schema": { "type": "string", "description": "Display rule ID." }, "required": true, "description": "Display rule ID." } ], "responses": { "200": { "description": "The display rule was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveDisplayRuleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/display-rules/reorder": { "post": { "operationId": "reorderLeagueDisplayRules", "tags": [ "League: Rules & Config" ], "summary": "Reorder league display rules", "description": "Reorders display rules for a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league display_rules capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderDisplayRulesRequestBody" } } } }, "responses": { "200": { "description": "The display rules were reordered.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderDisplayRulesResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/display-rules/upsert": { "post": { "operationId": "upsertLeagueDisplayRule", "tags": [ "League: Rules & Config" ], "summary": "Upsert a league display rule", "description": "Creates or updates an informational display rule for a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league display_rules capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertDisplayRuleRequestBody" } } } }, "responses": { "200": { "description": "The display rule was upserted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertDisplayRuleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/games": { "post": { "operationId": "getLeagueGames", "tags": [ "League Discovery" ], "summary": "Get league games", "description": "Returns games configured for a league resolved by slug or Convex ID. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "responses": { "200": { "description": "League games.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueGames" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/games/{leagueGameId}": { "delete": { "operationId": "removeLeagueGame", "tags": [ "League: Rules & Config" ], "summary": "Remove a league game", "description": "Removes a game from a league and deletes its non-active league configuration. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league games capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "leagueGameId", "schema": { "type": "string", "description": "League game link ID." }, "required": true, "description": "League game link ID." } ], "responses": { "200": { "description": "The game was removed from the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveLeagueGameResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/games/{leagueGameId}/toggle": { "post": { "operationId": "toggleLeagueGame", "tags": [ "League: Rules & Config" ], "summary": "Toggle a league game", "description": "Activates or deactivates a league game. Deactivation cancels pending, accepted, and ready matches for that league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league games capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "leagueGameId", "schema": { "type": "string", "description": "League game link ID." }, "required": true, "description": "League game link ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToggleLeagueGameRequestBody" } } } }, "responses": { "200": { "description": "The league game was toggled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToggleLeagueGameResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/games/add": { "post": { "operationId": "addLeagueGame", "tags": [ "League: Rules & Config" ], "summary": "Add a league game", "description": "Adds an active game to a league. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league games capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddLeagueGameRequestBody" } } } }, "responses": { "200": { "description": "The game was added to the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueGameWriteResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/matches/{matchId}/player-stats": { "post": { "operationId": "submitLeaguePlayerStats", "tags": [ "League: Scores" ], "summary": "Submit or update league player stats for a map", "description": "Sets per-player stats on an existing league match map score. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league scores capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GamePlayerStatsBody" } } } }, "responses": { "200": { "description": "The league player stats were updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GamePlayerStatsResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/matches/{matchId}/scores": { "post": { "operationId": "submitLeagueScores", "tags": [ "League: Scores" ], "summary": "Submit league match scores in a batch", "description": "Submits scores for one or more maps in a league match; league admin scores are auto-confirmed. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league scores capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchScoresBody" } } } }, "responses": { "200": { "description": "Per-map submission results. success is true only when every map was confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchScoresResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/matches/{matchId}/scores/{mapIndex}": { "post": { "operationId": "submitLeagueMapScore", "tags": [ "League: Scores" ], "summary": "Submit one league match map score", "description": "Submits the score for one map in a league match; league admin scores are auto-confirmed. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league scores capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." }, { "in": "path", "name": "mapIndex", "schema": { "type": "string", "description": "Zero-based index of the map within the series." }, "required": true, "description": "Zero-based index of the map within the series." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameSingleMapScoreBody" } } } }, "responses": { "200": { "description": "The map score was submitted and confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameSingleMapScoreResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/matches/{matchId}/status": { "patch": { "operationId": "updateLeagueMatchStatus", "tags": [ "League: Scores" ], "summary": "Update a league match's lifecycle status", "description": "Transitions a league match between lifecycle states. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league scores capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueStatusUpdateBody" } } } }, "responses": { "200": { "description": "The league match status was transitioned successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameStatusUpdateResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/matches/batch-scores": { "post": { "operationId": "submitLeagueBatchMatchScores", "tags": [ "League: Scores" ], "summary": "Submit league map scores across multiple matches", "description": "Submits map scores for up to 50 league match items in one request. Each item is independently checked to belong to the league in the path and returns a per-item result. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league scores capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchMatchScoresBody" } } } }, "responses": { "200": { "description": "Per-item submission results. success is true only when every item was confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameBatchMatchScoresResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/members": { "post": { "operationId": "getLeagueMembers", "tags": [ "League: Membership & Teams" ], "summary": "Get league staff members", "description": "Returns staff members for a league resolved by slug. The API key owner must have a MEMBER+ league role or be TeamBattles staff. Requires the leagues.league_admin:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "responses": { "200": { "description": "Staff members of the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueMembers" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/members/{memberId}/remove": { "post": { "operationId": "removeLeagueMember", "tags": [ "League: Membership & Teams" ], "summary": "Remove a league staff member", "description": "Deactivates a league staff membership. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league members capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "memberId", "schema": { "type": "string", "minLength": 1, "description": "League staff membership ID." }, "required": true, "description": "League staff membership ID." } ], "responses": { "200": { "description": "The league staff member was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveLeagueMemberResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/members/{memberId}/role": { "post": { "operationId": "updateLeagueMemberRole", "tags": [ "League: Membership & Teams" ], "summary": "Update a league staff member role", "description": "Updates a league staff member role. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league members capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "memberId", "schema": { "type": "string", "minLength": 1, "description": "League staff membership ID." }, "required": true, "description": "League staff membership ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueMemberRoleRequestBody" } } } }, "responses": { "200": { "description": "The league staff member role was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueMemberRoleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/members/add": { "post": { "operationId": "addLeagueMember", "tags": [ "League: Membership & Teams" ], "summary": "Add a league staff member", "description": "Adds or reactivates a league staff member. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league members capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddLeagueMemberRequestBody" } } } }, "responses": { "200": { "description": "The league staff member was added.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddLeagueMemberResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/ownership/transfer": { "post": { "operationId": "transferLeagueOwnership", "tags": [ "League: Membership & Teams" ], "summary": "Transfer league ownership", "description": "Transfers league ownership to another staff member. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.league_admin:read-write access on the key; Convex re-checks current OWNER authority. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferLeagueOwnershipRequestBody" } } } }, "responses": { "200": { "description": "League ownership was transferred.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferLeagueOwnershipResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/penalties": { "post": { "operationId": "getLeaguePenalties", "tags": [ "League: Moderation" ], "summary": "Get league penalties and cooldowns", "description": "Returns penalties and/or member cooldowns for a league resolved by slug, with optional filtering. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path (or TeamBattles staff), with leagues.league_admin:read access on the key. These admin reads no longer require a paid developer plan; they stay authority-gated (current league ADMIN) and rate-limited by the league owner's plan. League API WRITE routes still require the leagueOperatorApi feature (api_pro or higher) on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PenaltiesRequestBody" } } } }, "responses": { "200": { "description": "Penalties and cooldowns for the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaguePenalties" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/penalties/create": { "post": { "operationId": "createLeaguePenalty", "tags": [ "League: Moderation" ], "summary": "Create a league penalty", "description": "Issues a warning, match-forfeit penalty, or point deduction to a league team. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league penalties capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePenaltyRequestBody" } } } }, "responses": { "200": { "description": "The league penalty was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePenaltyResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/points/update": { "post": { "operationId": "updateLeaguePointsConfig", "tags": [ "League: Rules & Config" ], "summary": "Update league points config", "description": "Creates or updates the points configuration for a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league points capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePointsConfigRequestBody" } } } }, "responses": { "200": { "description": "The league points config was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePointsConfigResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/rules": { "post": { "operationId": "getLeagueRules", "tags": [ "League Discovery" ], "summary": "Get league rules and points config", "description": "Returns the game rules and points configuration for a league + game, resolved by league slug. Requires the leagues.league_public:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RulesRequestBody" } } } }, "responses": { "200": { "description": "Game rules and points config for the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueRules" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/rules/apply-template": { "post": { "operationId": "applyLeagueRuleTemplate", "tags": [ "League: Rules & Config" ], "summary": "Apply a league rule template", "description": "Applies a rule template to a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league rules capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplyRuleTemplateRequestBody" } } } }, "responses": { "200": { "description": "The rule template was applied.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplyRuleTemplateResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/rules/update": { "post": { "operationId": "updateLeagueRules", "tags": [ "League: Rules & Config" ], "summary": "Update league game rules", "description": "Creates or updates enforced rules for a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league rules capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateGameRulesRequestBody" } } } }, "responses": { "200": { "description": "The league game rules were updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuleWriteResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/season-options": { "post": { "operationId": "getLeagueSeasonOptions", "tags": [ "League Discovery" ], "summary": "Get league season options", "description": "Returns season selector options for a league game. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueSeasonOptionsRequestBody" } } } }, "responses": { "200": { "description": "League season options.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueSeasonOptions" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/seasons": { "post": { "operationId": "getLeagueSeasons", "tags": [ "League Discovery" ], "summary": "Get league seasons", "description": "Returns seasons for a league resolved by slug, with optional game and status filtering. Requires the leagues.league_public:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SeasonsRequestBody" } } } }, "responses": { "200": { "description": "Seasons for the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueSeasons" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/seasons/{seasonId}": { "delete": { "operationId": "deleteLeagueSeason", "tags": [ "League: Seasons" ], "summary": "Delete a league season", "description": "Deletes an upcoming league season. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league seasons capability enabled on the key. League API access is gated at api_pro on the league owner's plan. Replays are not deduped; existing state guards return the current state error if the season no longer exists or is no longer upcoming.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "seasonId", "schema": { "type": "string", "description": "League season ID." }, "required": true, "description": "League season ID." } ], "responses": { "200": { "description": "The season was deleted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteLeagueSeasonResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "getLeagueSeason", "tags": [ "League Discovery" ], "summary": "Get a league season", "description": "Returns a single season that belongs to the resolved league. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "seasonId", "schema": { "type": "string", "description": "League season ID." }, "required": true, "description": "League season ID." } ], "responses": { "200": { "description": "League season.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueSeason" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/seasons/{seasonId}/activate": { "post": { "operationId": "activateLeagueSeason", "tags": [ "League: Seasons" ], "summary": "Activate a league season", "description": "Activates an upcoming league season. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league seasons capability enabled on the key. League API access is gated at api_pro on the league owner's plan. Replays are not deduped; existing state guards return the current state error if the season is no longer upcoming.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "seasonId", "schema": { "type": "string", "description": "League season ID." }, "required": true, "description": "League season ID." } ], "responses": { "200": { "description": "The season was activated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivateLeagueSeasonResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/seasons/{seasonId}/complete": { "post": { "operationId": "completeLeagueSeason", "tags": [ "League: Seasons" ], "summary": "Complete a league season", "description": "Completes an active league season. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league seasons capability enabled on the key. League API access is gated at api_pro on the league owner's plan. Replays are not deduped; existing state guards return the current state error if the season is no longer active.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." }, { "in": "path", "name": "seasonId", "schema": { "type": "string", "description": "League season ID." }, "required": true, "description": "League season ID." } ], "responses": { "200": { "description": "The season was completed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompleteLeagueSeasonResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/seasons/create": { "post": { "operationId": "createLeagueSeason", "tags": [ "League: Seasons" ], "summary": "Create a league season", "description": "Creates an upcoming season for a league game. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league seasons capability enabled on the key. League API access is gated at api_pro on the league owner's plan. Supply an optional `Idempotency-Key` request header to make retries safe: an identical key and body replays the original season id, while the same key with a different body returns 409 error_idempotency_key_conflict.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSeasonRequestBody" } } } }, "responses": { "200": { "description": "The season was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSeasonResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/settings": { "post": { "operationId": "getLeagueSettings", "tags": [ "League: Rules & Config" ], "summary": "Get league settings", "description": "Returns full league settings for admin tooling. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.settings_read:read access on the key. These admin reads no longer require a paid developer plan; they stay authority-gated (current league ADMIN) and rate-limited by the league owner's plan. League API WRITE routes still require the leagueOperatorApi feature (api_pro or higher) on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "responses": { "200": { "description": "League settings.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueSettingsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/settings/enabled": { "post": { "operationId": "setLeagueEnabled", "tags": [ "League: Rules & Config" ], "summary": "Set league enabled state", "description": "Enables or disables a league. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.league_admin:read-write access on the key; Convex re-checks current OWNER authority. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetLeagueEnabledRequestBody" } } } }, "responses": { "200": { "description": "The league enabled state was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetLeagueEnabledResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/shutdown/request": { "post": { "operationId": "requestLeagueShutdown", "tags": [ "League: Rules & Config" ], "summary": "Request league shutdown", "description": "Requests TeamBattles staff review for league shutdown. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with leagues.league_admin:read-write access on the key; Convex re-checks current OWNER authority. Staff-only shutdown execution is not exposed by the public API. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "responses": { "200": { "description": "League shutdown was requested.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestLeagueShutdownResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/standings": { "post": { "operationId": "getLeagueStandings", "tags": [ "League Discovery" ], "summary": "Get league standings", "description": "Returns approved teams with their season stats, ranked by standings position, for a league resolved by slug. Requires the leagues.league_public:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug." }, "required": true, "description": "League slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StandingsRequestBody" } } } }, "responses": { "200": { "description": "League standings for the requested season.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueStandings" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/teams/{leagueTeamId}/approve": { "post": { "operationId": "approveLeagueTeamApplication", "tags": [ "League: Membership & Teams" ], "summary": "Approve a league team application", "description": "Approves a pending team application for the league. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league teams capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "leagueTeamId", "schema": { "type": "string", "minLength": 1, "description": "League team application ID." }, "required": true, "description": "League team application ID." } ], "responses": { "200": { "description": "The team application was approved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApproveLeagueTeamResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/teams/{leagueTeamId}/deny": { "post": { "operationId": "denyLeagueTeamApplication", "tags": [ "League: Membership & Teams" ], "summary": "Deny a league team application", "description": "Denies a pending team application for the league. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league teams capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "leagueTeamId", "schema": { "type": "string", "minLength": 1, "description": "League team application ID." }, "required": true, "description": "League team application ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DenyLeagueTeamRequestBody" } } } }, "responses": { "200": { "description": "The team application was denied.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DenyLeagueTeamResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/teams/{leagueTeamId}/remove": { "post": { "operationId": "removeLeagueTeam", "tags": [ "League: Membership & Teams" ], "summary": "Remove a league team", "description": "Removes an approved team from the league. Pending matches are cancelled and ready or accepted matches are forfeited by the removed team. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league teams capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "leagueTeamId", "schema": { "type": "string", "minLength": 1, "description": "Approved league team membership ID." }, "required": true, "description": "Approved league team membership ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveLeagueTeamRequestBody" } } } }, "responses": { "200": { "description": "The team was removed from the league.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveLeagueTeamResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/tickets/{ticketId}": { "patch": { "operationId": "updateLeagueTicket", "tags": [ "League: Tickets" ], "summary": "Update a league support ticket", "description": "Updates ticket status, priority, or assignment for a league-scoped support ticket. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league tickets capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "ticketId", "schema": { "type": "string", "description": "League ticket ID." }, "required": true, "description": "League ticket ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueTicketRequestBody" } } } }, "responses": { "200": { "description": "The ticket was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLeagueTicketResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/tickets/{ticketId}/escalate": { "post": { "operationId": "escalateLeagueTicket", "tags": [ "League: Tickets" ], "summary": "Escalate a league support ticket", "description": "Escalates a league-scoped support ticket to TeamBattles staff. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league tickets capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "ticketId", "schema": { "type": "string", "description": "League ticket ID." }, "required": true, "description": "League ticket ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EscalateLeagueTicketRequestBody" } } } }, "responses": { "200": { "description": "The ticket was escalated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EscalateLeagueTicketResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/tickets/{ticketId}/reply": { "post": { "operationId": "replyToLeagueTicket", "tags": [ "League: Tickets" ], "summary": "Reply to a league support ticket", "description": "Adds a reply or internal note to a league-scoped support ticket. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league tickets capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." }, { "in": "path", "name": "ticketId", "schema": { "type": "string", "description": "League ticket ID." }, "required": true, "description": "League ticket ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyLeagueTicketRequestBody" } } } }, "responses": { "200": { "description": "The ticket reply was added.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyLeagueTicketResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/{identifier}/tickets/create": { "post": { "operationId": "createLeagueTicket", "tags": [ "League: Tickets" ], "summary": "Create a league support ticket", "description": "Creates a league-scoped support ticket. Requires a personal or developer API key whose owner is currently a league ADMIN of the league in the path, with the league tickets capability enabled on the key. League API access is gated at api_pro on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "League slug or Convex league ID." }, "required": true, "description": "League slug or Convex league ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateLeagueTicketRequestBody" } } } }, "responses": { "200": { "description": "The ticket was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateLeagueTicketResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/leagues/templates": { "post": { "operationId": "getLeagueTemplates", "tags": [ "League Discovery" ], "summary": "Get league rule templates", "description": "Returns league rule templates visible to authenticated API clients, optionally filtered by game or official status. Requires leagues.league_public:read.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueTemplatesRequestBody" } } } }, "responses": { "200": { "description": "League rule templates.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeagueTemplates" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}": { "get": { "operationId": "getMatchDetail", "tags": [ "Match Discovery" ], "summary": "Get match detail", "description": "Returns a participant-gated match detail projection. Lobby codes and raw match documents are intentionally omitted. Requires one of matches.user_matches:read, matches.team_matches:read, or matches.org_matches:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "Match detail.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiMatchDetailResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/accept": { "post": { "operationId": "createMatchAcceptance", "tags": [ "My Matches" ], "summary": "Create a match acceptance request", "description": "Creates a match acceptance request as the personal API key owner. The owner must be a captain, co-captain, or org owner of the accepting team and the proposed roster must satisfy existing match rules. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptMatchRequestBody" } } } }, "responses": { "200": { "description": "The match acceptance request was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/acceptances/{acceptanceId}/approve": { "post": { "operationId": "approveMatchAcceptance", "tags": [ "My Matches" ], "summary": "Approve a match acceptance", "description": "Approves a pending match acceptance as the personal API key owner. The owner must be a captain, co-captain, or org owner of the creator team, and the acceptance must still be pending. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." }, { "in": "path", "name": "acceptanceId", "schema": { "type": "string", "description": "Match acceptance ID." }, "required": true, "description": "Match acceptance ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApproveAcceptanceRequestBody" } } } }, "responses": { "200": { "description": "The acceptance was approved successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApproveAcceptanceResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/acceptances/{acceptanceId}/decline": { "post": { "operationId": "declineMatchAcceptance", "tags": [ "My Matches" ], "summary": "Decline a match acceptance", "description": "Declines a pending match acceptance as the personal API key owner. The owner must be a captain, co-captain, or org owner of the creator team, and the acceptance must still be pending. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." }, { "in": "path", "name": "acceptanceId", "schema": { "type": "string", "description": "Match acceptance ID." }, "required": true, "description": "Match acceptance ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeclineAcceptanceRequestBody" } } } }, "responses": { "200": { "description": "The acceptance was declined successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeclineAcceptanceResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/attendance": { "post": { "operationId": "updateMatchAttendance", "tags": [ "My Matches" ], "summary": "Update match attendance", "description": "Updates the personal API key owner's own attendance status for a match. The owner must already be rostered in the match; the platform may swap active and bench players automatically. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAttendanceRequestBody" } } } }, "responses": { "200": { "description": "The attendance status was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAttendanceResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/cancel": { "post": { "operationId": "cancelMatch", "tags": [ "My Matches" ], "summary": "Cancel a match", "description": "Cancels a match as the personal API key owner. For a regular match the owner must be able to manage it (be a captain, co-captain, or org owner of a participating team, or an admin); past the league grace period an accepted league match is treated as a forfeit. For a PENDING challenge the owner must lead the creator team (captain, co-captain, or org owner of the challenging team), and past the challenge grace window (default 24h, league-overridable) cancelling any pending challenge - league or not - is recorded as a forfeit with the creator team taking the loss. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CancelMatchRequestBody" } } } }, "responses": { "200": { "description": "The match was cancelled successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CancelMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/challenges/accept": { "post": { "operationId": "acceptMatchChallenge", "tags": [ "My Matches" ], "summary": "Accept a match challenge", "description": "Accepts a pending challenge as the personal API key owner. The owner must be a captain, co-captain, or org owner of the challenged team and the proposed roster must satisfy existing match rules. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptChallengeRequestBody" } } } }, "responses": { "200": { "description": "The challenge was accepted successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptChallengeResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/challenges/refuse": { "post": { "operationId": "refuseMatchChallenge", "tags": [ "My Matches" ], "summary": "Refuse a match challenge", "description": "Refuses a pending challenge as the personal API key owner. The owner must be a captain, co-captain, or org owner of the challenged team. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefuseChallengeRequestBody" } } } }, "responses": { "200": { "description": "The challenge was refused successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefuseChallengeResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/chat": { "get": { "operationId": "listMatchChatMessages", "tags": [ "Match Chat" ], "summary": "List a match chat room's messages", "description": "Returns the messages of a match's chat room, newest first, with cursor pagination. The API key owner must be a participant of the match (a member of one of the match's teams); a non-participant receives 404. Requires the chat.read scope.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID. The caller must be a participant of this match." }, "required": true, "description": "Match ID. The caller must be a participant of this match." }, { "in": "query", "name": "limit", "schema": { "description": "Page size (1-100). Defaults to 50.", "type": "string" }, "description": "Page size (1-100). Defaults to 50." }, { "in": "query", "name": "cursor", "schema": { "description": "Opaque continuation cursor from a prior page's nextCursor.", "type": "string" }, "description": "Opaque continuation cursor from a prior page's nextCursor." } ], "responses": { "200": { "description": "Program cursor-paginated result. nextCursor is null when hasMore is false.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ChatMessage" } }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hasMore": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "data", "nextCursor", "hasMore", "timestamp" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "sendMatchChatMessage", "tags": [ "Match Chat" ], "summary": "Send a message to a match chat room", "description": "Sends a message to a match's chat room as the API key owner. The owner must be a participant of the match; a non-participant receives 403. Requires the chat.write scope and the writes feature. Supports the Idempotency-Key header.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID. The caller must be a participant of this match." }, "required": true, "description": "Match ID. The caller must be a participant of this match." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendChatMessageRequestBody" } } } }, "responses": { "200": { "description": "The message was sent.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendChatMessageResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/forfeit": { "post": { "operationId": "forfeitMatch", "tags": [ "My Matches" ], "summary": "Forfeit a match", "description": "Forfeits a match as the personal API key owner. The owner must be a captain, co-captain, or org owner of one participating team. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ForfeitMatchRequestBody" } } } }, "responses": { "200": { "description": "The match was forfeited successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ForfeitMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/lobby-code": { "post": { "operationId": "updateMatchLobbyCode", "tags": [ "My Matches" ], "summary": "Set a match lobby code", "description": "Sets or updates the lobby code as the personal API key owner. The owner must be a captain, co-captain, or org owner of one participating team. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLobbyCodeRequestBody" } } } }, "responses": { "200": { "description": "The match lobby code was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLobbyCodeResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/players": { "get": { "operationId": "getMatchPlayers", "tags": [ "Match Discovery" ], "summary": "Get match players", "description": "Returns participant-gated player rows for a match, including roster type and attendance state. Requires one of matches.user_matches:read, matches.team_matches:read, or matches.org_matches:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "Match player rows.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiMatchPlayersResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/publish": { "post": { "operationId": "publishMatch", "tags": [ "My Matches" ], "summary": "Publish a match", "description": "Publishes a draft match as the personal API key owner, making it visible for acceptance. The owner must be the match creator or a captain, co-captain, or org owner of the creating team, and the match must still be a draft. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "The match was published successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublishMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/ready": { "post": { "operationId": "markMatchReady", "tags": [ "My Matches" ], "summary": "Mark a match team ready", "description": "Marks a participating team ready as the personal API key owner. The owner must be a captain, co-captain, or org owner of the team. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MarkMatchReadyRequestBody" } } } }, "responses": { "200": { "description": "The team readiness state was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MarkMatchReadyResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/scores": { "get": { "operationId": "getMatchScores", "tags": [ "Match Discovery" ], "summary": "Get all map scores", "description": "Retrieve every map score for a match plus a series summary. Returns the full unpaginated list of map scores (no cursor or limit) and a seriesScore counting map wins per side, computed only from CONFIRMED maps and awarding a map to the side with the strictly higher score (equal scores count for neither). Each score's scoreStatus is CONFIRMED or PENDING; submittedBy, confirmedBy, and createdAt may be null. Screenshot URLs are suppressed (empty array) for any score whose API-uploaded image has not passed content moderation. Requires one of matches.user_matches:read, matches.team_matches:read, or matches.org_matches:read. The caller must be an active member of one of the match's two teams; non-participants receive 403, unless they hold a TeamBattles staff role, which can read any match's scores.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match id." }, "required": true, "description": "Match id." } ], "responses": { "200": { "description": "All map scores for the match with a series summary.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MapScores" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "confirmMatchScores", "tags": [ "My Matches" ], "summary": "Confirm a map score", "description": "Confirm a map score submitted by the opposing team. Only a captain, co-captain, or org owner of the opposing team can confirm (cannot confirm own team's submission). Requires the matches.team_matches:read-write permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match id." }, "required": true, "description": "Match id." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfirmScoreBody" } } } }, "responses": { "200": { "description": "Map score confirmed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScoreSubmissionResult" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "submitMatchScores", "tags": [ "My Matches" ], "summary": "Submit a map score", "description": "Submit or overwrite a map score for a match. Only a captain, co-captain, or org owner of a participating team can submit. Requires the matches.team_matches:read-write permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match id." }, "required": true, "description": "Match id." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitScoreBody" } } } }, "responses": { "200": { "description": "Map score submitted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScoreSubmissionResult" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/{matchId}/start": { "post": { "operationId": "startMatch", "tags": [ "My Matches" ], "summary": "Start a match", "description": "Starts a ready match as the personal API key owner, moving it to in-progress. The owner must be a captain, co-captain, or org owner of the creating or accepted team, and the match must be in the ready state. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "matchId", "schema": { "type": "string", "description": "Match ID." }, "required": true, "description": "Match ID." } ], "responses": { "200": { "description": "The match was started successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/create": { "post": { "operationId": "createMatch", "tags": [ "My Matches" ], "summary": "Create a match", "description": "Creates a new match as the personal API key owner. The owner must be a captain, co-captain, or org owner of the creator team and the active roster must be members of that team. League and challenge rules are enforced exactly as in the web app. Requires matches.user_matches:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateMatchRequestBody" } } } }, "responses": { "200": { "description": "The match was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateMatchResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/matches/discover": { "post": { "operationId": "discoverMatches", "tags": [ "Match Discovery" ], "summary": "Discover open matches", "description": "Returns published pending open matches. League matches are excluded unless leagueId is provided. gameId and gameSlug are mutually exclusive. Requires matches.public_matches:read.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MatchDiscoverBody" } } } }, "responses": { "200": { "description": "Discoverable open matches.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MatchDiscoverPage" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs": { "post": { "operationId": "createOrg", "tags": [ "My Organizations" ], "summary": "Create an organization", "description": "Creates a new organization as the personal API key owner. The owner becomes the organization owner. Role ceilings and cascades are enforced exactly as in the web app. Requires orgs.profile:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrgBody" } } } }, "responses": { "200": { "description": "The organization was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrgResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}": { "delete": { "operationId": "deleteOrganization", "tags": [ "My Organizations" ], "summary": "Delete an organization", "description": "Deletes an organization. The caller (key owner) must be the organization owner. Requires orgs.profile:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "responses": { "200": { "description": "Organization deleted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteOrgResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "get": { "operationId": "getOrganizationProfile", "tags": [ "Organizations" ], "summary": "Get an organization profile", "description": "Returns an API-safe organization profile projection. Active organization members are treated as public visibility for their own organization. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "responses": { "200": { "description": "Organization profile.", "content": { "application/json": { "schema": { "type": "object", "properties": { "organization": { "$ref": "#/components/schemas/ApiOrganizationProfile" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "organization", "timestamp" ], "additionalProperties": false, "description": "Envelope containing organization plus a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "updateOrganization", "tags": [ "My Organizations" ], "summary": "Update an organization", "description": "Updates an organization's profile fields. The caller (key owner) must be an organization owner or admin. Requires orgs.profile:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateOrgBody" } } } }, "responses": { "200": { "description": "Organization updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateOrgResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/matches": { "post": { "operationId": "listOrgMatches", "tags": [ "Match Discovery" ], "summary": "List an organization's matches", "description": "Returns matches across all teams in an organization (resolved by id or slug), newest first, with cursor pagination. The authenticated user must be an active member of the organization. Requires the matches.org_matches:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization id or slug." }, "required": true, "description": "Organization id or slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MatchesRequestBody" } } } }, "responses": { "200": { "description": "Cursor-paginated result. continueCursor is non-null even when isDone is true.", "content": { "application/json": { "schema": { "type": "object", "properties": { "page": { "type": "array", "items": { "$ref": "#/components/schemas/UserMatch" } }, "isDone": { "type": "boolean" }, "continueCursor": { "type": "string" } }, "required": [ "page", "isDone", "continueCursor" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/members": { "get": { "operationId": "listOrganizationMembers", "tags": [ "Organizations" ], "summary": "List active organization members", "description": "Returns every active member of the organization in a single response. This list is not paginated and accepts no limit or cursor parameter. Members are sorted by role (owner first, then admin, manager, and member; unrecognized roles tie with member). Each row's `id` is the membership row ID, not the user ID, and the row carries the member's API-safe user profile, role label, and join timestamp. Visible only when the organization profile is public, or when the API key owner is an active member of the organization; otherwise this returns 403. A non-existent or inactive organization returns 404. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "responses": { "200": { "description": "Organization members.", "content": { "application/json": { "schema": { "type": "object", "properties": { "members": { "type": "array", "items": { "$ref": "#/components/schemas/ApiMember" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "members", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing members, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "addOrganizationMember", "tags": [ "My Organizations" ], "summary": "Add an organization member", "description": "Adds a user to the organization with the ADMIN or MEMBER role. The caller (key owner) must be an organization admin or owner. Role ceilings and cascades are enforced exactly as in the web app. Requires orgs.roster:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddOrgMemberBody" } } } }, "responses": { "200": { "description": "The member was added.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddOrgMemberResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/members/{userId}": { "delete": { "operationId": "removeOrgMember", "tags": [ "My Organizations" ], "summary": "Remove an organization member", "description": "Removes a member from an organization. The caller (key owner) must be an organization admin. The organization owner cannot be removed this way - transfer ownership first. Requires orgs.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." }, { "in": "path", "name": "userId", "schema": { "type": "string", "description": "Convex user ID of the member to remove." }, "required": true, "description": "Convex user ID of the member to remove." } ], "responses": { "200": { "description": "Member removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveOrgMemberResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/members/{userId}/role": { "patch": { "operationId": "setOrgMemberRole", "tags": [ "My Organizations" ], "summary": "Set an organization member's role", "description": "Sets an organization member's role to ADMIN, MANAGER, or MEMBER. The caller (key owner) must be the organization owner. The owner role cannot be assigned or removed this way - use ownership transfer instead. Requires orgs.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." }, { "in": "path", "name": "userId", "schema": { "type": "string", "description": "Convex user ID of the member whose role is changing." }, "required": true, "description": "Convex user ID of the member whose role is changing." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetOrgMemberRoleBody" } } } }, "responses": { "200": { "description": "Member role updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetOrgMemberRoleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/ownership/transfer": { "post": { "operationId": "transferOrgOwnership", "tags": [ "My Organizations" ], "summary": "Transfer organization ownership", "description": "Transfers organization ownership from the caller (key owner) to another active member, who becomes the new owner. The caller must currently be the organization owner and is demoted to admin. Requires orgs.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferOrgOwnershipBody" } } } }, "responses": { "200": { "description": "Ownership transferred.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferOrgOwnershipResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/stats": { "get": { "operationId": "getOrganizationStats", "tags": [ "Organizations" ], "summary": "Get organization aggregate stats", "description": "Returns an organization's aggregate competitive stats by slug or organization ID. Stats are returned when the organization profile is limited or public, or when the API key owner is an active organization member (members can read stats for a private org too); a private organization viewed by a non-member returns 403, and an inactive or unknown organization returns 404. `teams` and `members` count only active, enabled teams and active members. `wins`, `losses`, and `matchesPlayed` are aggregated across the organization's active, enabled teams. `winRate` is wins divided by matchesPlayed and is 0 when no matches have been played. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "responses": { "200": { "description": "Organization stats.", "content": { "application/json": { "schema": { "type": "object", "properties": { "stats": { "$ref": "#/components/schemas/ApiOrganizationStats" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "stats", "timestamp" ], "additionalProperties": false, "description": "Envelope containing stats plus a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/{identifier}/teams": { "get": { "operationId": "listOrganizationTeams", "tags": [ "Organizations" ], "summary": "List organization teams", "description": "Returns an organization's active teams, resolved by slug or organization ID. Readable when the organization is public or the API key owner is an active member - otherwise responds 403. Members see all active teams; non-members do not receive private or disabled teams. The full result set is returned in one response with a count - there is no pagination, limit, or guaranteed sort order. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Organization slug or Convex organization ID." }, "required": true, "description": "Organization slug or Convex organization ID." } ], "responses": { "200": { "description": "Organization teams.", "content": { "application/json": { "schema": { "type": "object", "properties": { "teams": { "type": "array", "items": { "$ref": "#/components/schemas/ApiTeamSummary" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "teams", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing teams, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/orgs/discover": { "get": { "operationId": "discoverOrganizations", "tags": [ "Organizations" ], "summary": "Discover public organizations", "description": "Returns a neutral, ranked discovery list of active, public, non-disabled organizations. Each result is a small summary (id, slug, name, tag, avatarUrl, visibility); `count` is the size of the returned page, not a total. Results are sorted featured organizations first, then by most wins, then newest. `limit` is 1-100 (default 50); ranking is computed over at most the first 1000 candidate organizations and there is no cursor pagination, so the response is a single ranked page. `search` filters by case-insensitive name substring and is only applied when it is at least 2 characters (shorter values are ignored). Unlike an in-app feed, results do not exclude organizations the API key owner belongs to and do not include membership or join-request flags. Requires orgs.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "search", "schema": { "description": "Optional organization name search.", "type": "string" }, "description": "Optional organization name search." }, { "in": "query", "name": "limit", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } } ], "responses": { "200": { "description": "Discoverable organizations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "organizations": { "type": "array", "items": { "$ref": "#/components/schemas/ApiOrganizationSummary" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "organizations", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing organizations, count, and a response timestamp." } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/strategies/{slug}": { "get": { "operationId": "getStrategyBySlug", "tags": [ "Strategies" ], "summary": "Get a strategy by share slug", "description": "Returns a shareable strategy resolved by its public share slug. Public and unlisted strategies are returned to any caller; a private strategy returns 404 unless the API key owner owns it. Requires strategies.read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "slug", "schema": { "type": "string", "description": "Strategy public share slug." }, "required": true, "description": "Strategy public share slug." } ], "responses": { "200": { "description": "The strategy.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiStrategyEnvelope" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/strategies/{slug}/shapes": { "get": { "operationId": "getStrategyShapes", "tags": [ "Strategies" ], "summary": "Get the shapes of a strategy by share slug", "description": "Returns the canvas shapes of a shareable strategy resolved by its public share slug, ordered by stacking index (zIndex). Hidden working shapes are omitted. The full set is returned in a single response - there is no pagination - and the read is bounded to the first 2000 rows in stacking order, so a board larger than that is truncated. The same visibility gate as the strategy read applies (private returns 404 unless the API key owner owns it; public and unlisted are readable by any key). Requires strategies.read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "slug", "schema": { "type": "string", "description": "Strategy public share slug." }, "required": true, "description": "Strategy public share slug." } ], "responses": { "200": { "description": "The strategy shapes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiStrategyShapesEnvelope" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/streams/live-status": { "post": { "operationId": "batchStreamStatus", "tags": [ "Streaming" ], "summary": "Batch live-stream status lookup", "description": "Filtered read returning compact live status for a batch of users (POST is used only to carry the id list; no data is written). Send a body of 1 - 50 Convex user IDs; duplicates are ignored and over-50 is rejected. Each response row is { id, isLive, platforms } and does not include the primaryStream detail returned by GET /users/{identifier}/stream. Users that do not exist, are banned, or whose profile hides stream status from the caller are omitted from the response (the batch never reveals which case applied or that a hidden user exists), so count may be less than the number of IDs sent. Unlike the single-user stream endpoint, IDs are matched by user ID only; usernames are not resolved. No pagination and no guaranteed ordering. Requires stream.read.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiBatchStreamStatusBody" } } } }, "responses": { "200": { "description": "Per-user live status for the visible subset of requested users.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiBatchStreamStatusEnvelope" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams": { "post": { "operationId": "createTeam", "tags": [ "My Teams" ], "summary": "Create a team", "description": "Creates a new team as the personal API key owner. The owner must manage the owning organization. Role ceilings and cascades are enforced exactly as in the web app. Requires teams.profile:read-write and API writes access. Supports an optional `Idempotency-Key` header for safe retries.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTeamBody" } } } }, "responses": { "200": { "description": "The team was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTeamResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}": { "delete": { "operationId": "disbandTeam", "tags": [ "My Teams" ], "summary": "Disband a team", "description": "Disbands a team (soft-deletes it and deactivates its members). The caller (key owner) must be the team captain. Requires teams.profile:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." } ], "responses": { "200": { "description": "Team disbanded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DisbandTeamResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "get": { "operationId": "getTeamProfile", "tags": [ "Teams" ], "summary": "Get a team profile", "description": "Returns an API-safe team profile projection. Active team members are treated as public visibility for their own team. Requires teams.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." } ], "responses": { "200": { "description": "Team profile.", "content": { "application/json": { "schema": { "type": "object", "properties": { "team": { "$ref": "#/components/schemas/ApiTeamProfile" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "team", "timestamp" ], "additionalProperties": false, "description": "Envelope containing team plus a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "updateTeam", "tags": [ "My Teams" ], "summary": "Update a team", "description": "Updates a team's profile fields. The caller (key owner) must be the team captain. Requires teams.profile:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTeamBody" } } } }, "responses": { "200": { "description": "Team updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTeamResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}/captaincy/transfer": { "post": { "operationId": "transferTeamCaptaincy", "tags": [ "My Teams" ], "summary": "Transfer team captaincy", "description": "Transfers team captaincy from the caller (key owner) to another active member, who becomes the new captain. The caller must currently be the team captain and is demoted to co-captain. Requires teams.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferTeamCaptaincyBody" } } } }, "responses": { "200": { "description": "Captaincy transferred.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferTeamCaptaincyResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}/matches": { "post": { "operationId": "listTeamMatches", "tags": [ "Match Discovery" ], "summary": "List a team's matches", "description": "Returns matches for a specific team (resolved by id or slug), newest first, with cursor pagination. The authenticated user must be an active member of the team. Requires the matches.team_matches:read permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team id or slug." }, "required": true, "description": "Team id or slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MatchesRequestBody" } } } }, "responses": { "200": { "description": "Cursor-paginated result. continueCursor is non-null even when isDone is true.", "content": { "application/json": { "schema": { "type": "object", "properties": { "page": { "type": "array", "items": { "$ref": "#/components/schemas/UserMatch" } }, "isDone": { "type": "boolean" }, "continueCursor": { "type": "string" } }, "required": [ "page", "isDone", "continueCursor" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}/members": { "get": { "operationId": "listTeamMembers", "tags": [ "Teams" ], "summary": "List active team members", "description": "Returns the full active roster when the team is public or the API key owner is an active team member; otherwise responds 403. The team is resolved by slug or Convex team ID and must be active, returning 404 if not found. Rows are sorted by role - captains first, then co-captains, then members - and each row's id is the membership row ID, not the user ID. Not paginated: every active member is returned in one response with a count, and there is no limit, cursor, or page token. Requires teams.roster:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." } ], "responses": { "200": { "description": "Team members.", "content": { "application/json": { "schema": { "type": "object", "properties": { "members": { "type": "array", "items": { "$ref": "#/components/schemas/ApiMember" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "members", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing members, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}/members/{userId}": { "delete": { "operationId": "removeTeamMember", "tags": [ "My Teams" ], "summary": "Remove a team member", "description": "Removes a member from a team, or removes yourself to leave it. To remove another member, the caller (key owner) must be the team captain or co-captain; any member may remove themselves. The team captain cannot be removed this way - disband the team or transfer captaincy first. Requires teams.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." }, { "in": "path", "name": "userId", "schema": { "type": "string", "description": "Convex user ID of the member to remove." }, "required": true, "description": "Convex user ID of the member to remove." } ], "responses": { "200": { "description": "Member removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveTeamMemberResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{identifier}/members/{userId}/role": { "patch": { "operationId": "setTeamMemberRole", "tags": [ "My Teams" ], "summary": "Set a team member's role", "description": "Sets a team member's role to CO_CAPTAIN or MEMBER. The caller (key owner) must be the team captain or co-captain. The captain role cannot be assigned or removed this way - use captaincy transfer instead. Requires teams.roster:read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Team slug or Convex team ID." }, "required": true, "description": "Team slug or Convex team ID." }, { "in": "path", "name": "userId", "schema": { "type": "string", "description": "Convex user ID of the member whose role is changing." }, "required": true, "description": "Convex user ID of the member whose role is changing." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetTeamMemberRoleBody" } } } }, "responses": { "200": { "description": "Member role updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetTeamMemberRoleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tickets": { "get": { "operationId": "listTickets", "tags": [ "Support" ], "summary": "List the API key owner's support tickets", "description": "Returns the API key owner's tickets, newest first, with cursor pagination. Requires the tickets.read scope.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "limit", "schema": { "description": "Page size (1-100). Defaults to 25.", "type": "string" }, "description": "Page size (1-100). Defaults to 25." }, { "in": "query", "name": "cursor", "schema": { "description": "Opaque continuation cursor from a prior page's nextCursor.", "type": "string" }, "description": "Opaque continuation cursor from a prior page's nextCursor." } ], "responses": { "200": { "description": "Program cursor-paginated result. nextCursor is null when hasMore is false.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/TicketSummary" } }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hasMore": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "data", "nextCursor", "hasMore", "timestamp" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "createTicket", "tags": [ "Support" ], "summary": "Create a support ticket", "description": "Creates a support ticket owned by the API key owner. Requires the tickets.write scope and the writes feature. Supports the Idempotency-Key header.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTicketRequestBody" } } } }, "responses": { "200": { "description": "The ticket was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTicketResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tickets/{ticketId}": { "get": { "operationId": "getTicket", "tags": [ "Support" ], "summary": "Get one of the API key owner's tickets", "description": "Returns one of the API key owner's tickets and its message thread (internal staff notes excluded). A ticket the owner does not own reads as 404. Requires the tickets.read scope.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "ticketId", "schema": { "type": "string", "description": "Ticket ID." }, "required": true, "description": "Ticket ID." } ], "responses": { "200": { "description": "The ticket and its message thread.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TicketDetail" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tickets/{ticketId}/messages": { "post": { "operationId": "addTicketMessage", "tags": [ "Support" ], "summary": "Reply to one of the API key owner's tickets", "description": "Adds a reply message to one of the API key owner's tickets. Closed tickets are rejected. Requires the tickets.write scope and the writes feature. Supports the Idempotency-Key header.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "ticketId", "schema": { "type": "string", "description": "Ticket ID." }, "required": true, "description": "Ticket ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddTicketMessageRequestBody" } } } }, "responses": { "200": { "description": "The reply was added.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddTicketMessageResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments": { "post": { "operationId": "createTournament", "tags": [ "Tournament: Lifecycle" ], "summary": "Create a tournament", "description": "Creates a tournament as a DRAFT with approval status NOT_SUBMITTED. Nothing is public yet: call submit-for-approval, then open registration once staff approve.\n\nHOST AUTHORITY. `hostType` and `hostId` are yours to choose, but not to invent - you must actually hold the authority you name, or the request is refused. `user` requires `hostId` to be your own user id (otherwise 403 error_forbidden); `org` requires an active OWNER or ADMIN membership of that organization (otherwise 403 error_not_org_admin); `league` requires an active league ADMIN or OWNER membership (otherwise 403 error_league_admin_required). You must also be eligible to host at all - a paid plan, or an account at least 30 days old, and not competitively banned - or the request is 403 error_not_eligible_to_host.\n\nBILLING. Creation is billed to YOU, the key owner, because there is no tournament yet to resolve a host from. From this point on the billing flips: every organizer request against the tournament is billed to the HOST - the organization owner or the league owner - including requests made by tournament staff you add later. Choosing a host is therefore the act that binds that person's developer plan, which is exactly why the authority check above is strict.\n\nUnlike the rest of the tournament family this endpoint takes no `identifier`, so it is caller-billed and requires only the tournaments lifecycle capability on the key plus the tournamentOrganizerApi feature on your own plan.\n\nSupply an optional `Idempotency-Key` request header to make retries safe: an identical key and body replays the original tournament id and slug without creating a second tournament, while the same key with a different body returns 409 error_idempotency_key_conflict. Without the header a retried request creates a SECOND tournament, because a tournament has no natural key to collapse on.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCreateRequestBody" } } } }, "responses": { "200": { "description": "The draft tournament was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCreateResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}": { "get": { "operationId": "getTournament", "tags": [ "Tournament Discovery" ], "summary": "Get a tournament", "description": "Returns the profile for a single tournament, resolved by slug. A tournament you may not view answers 404, identically to an unknown slug. Manager-private review fields are included only when the caller manages the tournament. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The tournament profile.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentProfileResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/activity-feed": { "get": { "operationId": "getTournamentActivityFeed", "tags": [ "Tournament: Lifecycle" ], "summary": "Get tournament activity feed", "description": "Returns the tournament's organizer audit log, newest first, resolved by slug. This is a single limit-capped window over the most recent entries and is NOT cursor-paginated - there is no way to page past the newest 100 in v1, so poll and diff on `id`. `action` is open-ended and grows with new organizer surfaces; treat an unrecognised value as informational. Requires tournaments.tournament_admin:read on the key AND that the caller manages the tournament - the host, a tournament ADMIN, or a tournament MODERATOR. Tournament API access is gated at api_pro on the tournament HOST OWNER's personal developer plan. An organization holding a consumer subscription does not satisfy this - the developer plan ladder has no organization arm.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "query", "name": "limit", "schema": { "description": "Maximum entries to return, 1-100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 }, "description": "Maximum entries to return, 1-100. Defaults to 50." } ], "responses": { "200": { "description": "The tournament activity feed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentActivityFeedResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/applications": { "get": { "operationId": "listTournamentApplications", "tags": [ "Tournament: Registration" ], "summary": "List pending tournament applications", "description": "Returns the teams awaiting organizer review, resolved by slug. Requires tournaments.tournament_admin:read on the key AND that the caller manages the tournament - the host, a tournament ADMIN, or a tournament MODERATOR. A caller without that standing answers 403; a tournament they cannot view at all answers 404. Tournament API access is gated at api_pro on the tournament HOST OWNER's personal developer plan. An organization holding a consumer subscription does not satisfy this - the developer plan ladder has no organization arm.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "Pending applications.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentApplicationsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/applications/{participantId}/approve": { "post": { "operationId": "approveTournamentApplication", "tags": [ "Tournament: Registration" ], "summary": "Approve a tournament application", "description": "Approves a PENDING application, moving the team into the tournament and incrementing the participant count. Answers 409 error_tournament_full when the tournament is at capacity and 400 error_invalid_input when the application is not pending. Requires the tournaments registration capability and MANAGER authority on the tournament - a tournament MODERATOR qualifies. A participant belonging to another tournament answers 404, identically to an unknown one.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "responses": { "200": { "description": "The application was approved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/applications/{participantId}/deny": { "post": { "operationId": "denyTournamentApplication", "tags": [ "Tournament: Registration" ], "summary": "Deny a tournament application", "description": "Denies a PENDING application and notifies the applying captain, quoting `reason` when supplied. Answers 400 error_invalid_input when the application is not pending. Requires the tournaments registration capability and MANAGER authority on the tournament - a tournament MODERATOR qualifies.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentDenyApplicationBody" } } } }, "responses": { "200": { "description": "The application was denied.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/bracket": { "get": { "operationId": "getTournamentBracket", "tags": [ "Tournament Discovery" ], "summary": "Get a tournament bracket", "description": "Returns the rounds, bracket nodes, and participant display map for a tournament, resolved by slug. Empty until the tournament starts and matches are generated. A tournament you may not view answers 404. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The tournament bracket.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentBracketResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/cancel": { "post": { "operationId": "cancelTournament", "tags": [ "Tournament: Lifecycle" ], "summary": "Cancel a tournament", "description": "Cancels a tournament. IRREVERSIBLE - there is no un-cancel, and a COMPLETED or already CANCELLED tournament answers 400. Cancelling delists the tournament, emits a `tournament.cancelled` webhook, system-cancels every non-terminal generated match with no forfeit penalty, and notifies the captains of every approved participant. It does NOT change the approval status, so the response reports lifecycle status and approval status as independent fields. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCancelRequestBody" } } } }, "responses": { "200": { "description": "The tournament was cancelled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCancelResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agency/me": { "delete": { "operationId": "leaveTournamentFreeAgentPool", "tags": [ "Tournament Free Agency" ], "summary": "Remove yourself from the free-agent pool", "description": "Withdraws the API key owner from a tournament's free-agent pool. Not being in the pool at all answers 400 error_invalid_input.\n\nORDERING MATTERS AFTER A PICKUP. Once a team's offer has been accepted your pool row is PICKED_UP and you hold a roster entry on that team, and this endpoint refuses with 400 error_invalid_input until you are off that roster. Ask the team to drop you (or the organizer to remove the team) first; when a participant leaves the tournament its picked-up agents are released automatically.\n\nLeaving expires every PENDING pickup offer addressed to you in this tournament, and expired offers are never revived - if you rejoin the pool later, captains must offer again. Re-read GET /tournaments/{identifier}/me rather than reusing a cached offer list.\n\nRequires the tournaments actor free_agency capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "You are out of the pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "joinTournamentFreeAgentPool", "tags": [ "Tournament Free Agency" ], "summary": "List yourself as a free agent", "description": "Adds the API key owner to a tournament's solo free-agent pool, where captains can browse and make pickup offers. The path segment is literally 'me' - the pool row is keyed to the authenticated key owner and there is no way to list anyone else.\n\nThe tournament must have free agency enabled and still be open to joins, or the request answers 400 error_registration_closed. If the tournament's game requires a linked account (for example a Riot or Battle.net connection) and yours is missing, the request answers 403 error_free_agent_account_required - link it on your profile and retry.\n\nONE ROW PER TOURNAMENT. If you are already listed as AVAILABLE, or have been PICKED_UP by a team, the request answers 409 error_free_agent_already_in_pool. Once your previous row is terminal (you withdrew, or an organizer removed you) this endpoint reuses it rather than creating a second, so your history stays a single row. Leaving a team's roster is what releases a PICKED_UP row back to AVAILABLE; you do not rejoin manually after a pickup.\n\nRequires the tournaments actor free_agency capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentFreeAgencyJoinBody" } } } }, "responses": { "200": { "description": "You are listed in the pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agency/offers/{offerId}/respond": { "post": { "operationId": "respondToTournamentFreeAgentOffer", "tags": [ "Tournament Free Agency" ], "summary": "Accept or decline a free-agent pickup offer", "description": "Answers a pickup offer addressed to you as a free agent. You must be the offer's recipient - an offerId addressed to anyone else answers 403 - and the offer must still be PENDING, or the request answers 409 error_free_agent_offer_not_pending.\n\nACCEPTING JOINS THE TEAM. Your pool row becomes PICKED_UP, you are added to the offering team's tournament roster as a FREE_AGENT entry, and every other PENDING offer addressed to you in this tournament is expired - you are off the market. Re-read GET /tournaments/{identifier}/me afterwards rather than patching a cached offer list. Leaving that roster is also the only way back to AVAILABLE; the leave-pool endpoint refuses while you are rostered.\n\nAN OFFER CAN LAPSE BETWEEN BEING SENT AND ANSWERED - the tournament may have started, you may have been picked up elsewhere, or the offering team may have left. When accepting finds any of those, the offer is durably marked EXPIRED and the request answers 409 error_free_agent_offer_not_pending, the same code as an already-answered offer. It never answers 200 with accepted false, so a client can rely on a 2xx meaning the pickup really happened. Retrying answers identically.\n\nDECLINING IS ALWAYS AVAILABLE and notifies the captain who offered. The competitive-ban gate applies only to acceptance: a banned agent can clear an offer but receives 403 error_competitive_banned if they try to accept it.\n\nOffer IDs are returned by GET /tournaments/{identifier}/me. Requires the tournaments actor free_agency capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "offerId", "schema": { "type": "string", "description": "Free-agent pickup offer ID, as returned by GET /tournaments/{identifier}/me - inbound offers under `offers`." }, "required": true, "description": "Free-agent pickup offer ID, as returned by GET /tournaments/{identifier}/me - inbound offers under `offers`." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentOfferRespondBody" } } } }, "responses": { "200": { "description": "The response was recorded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentOfferRespondResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agency/offers/{offerId}/revoke": { "post": { "operationId": "revokeTournamentFreeAgentOffer", "tags": [ "Tournament Free Agency" ], "summary": "Revoke a pickup offer your team sent", "description": "Withdraws a pending free-agent pickup offer that one of your teams sent. Authority is the SENDING side of the offer: you must be the captain, co-captain, or organization owner of the team that made it, which is the mirror of the respond endpoint, where only the agent the offer is addressed to may act.\n\nThe offer must still be PENDING. One that has been accepted, declined, expired, or already revoked answers 409 error_free_agent_offer_not_pending - so unlike check-in this is not retry-safe, and a second call after a successful one is a conflict rather than a no-op. Use it to free yourself to send a fresh offer to the same agent, which is otherwise blocked by 409 error_free_agent_offer_exists.\n\nRevoking is silent: the agent is not notified, the offer simply disappears from their inbox. Nothing is rostered or released, because a pending offer never rostered anyone.\n\nAn offerId belonging to a different tournament answers 404 error_tournament_not_found. Requires the tournaments actor free_agency capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "offerId", "schema": { "type": "string", "description": "Free-agent pickup offer ID, as returned by GET /tournaments/{identifier}/me - inbound offers under `offers`." }, "required": true, "description": "Free-agent pickup offer ID, as returned by GET /tournaments/{identifier}/me - inbound offers under `offers`." } ], "responses": { "200": { "description": "The offer was revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agents": { "get": { "operationId": "listTournamentFreeAgents", "tags": [ "Tournament Discovery" ], "summary": "List tournament free agents", "description": "Returns the players currently AVAILABLE in the tournament free-agent pool, resolved by slug. Pass `viewerParticipantId` to have each agent stamped with whether that participant already has an open offer out to them; the id is re-authorized server-side and an unauthorized or stale value simply yields no stamps. A tournament you may not view answers 404. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "query", "name": "viewerParticipantId", "schema": { "description": "Participant ID whose open offers should be reflected in `viewerOfferStatus`. The caller must lead that participant's team and the participant must belong to this tournament, otherwise the field is null for every agent.", "type": "string" }, "description": "Participant ID whose open offers should be reflected in `viewerOfferStatus`. The caller must lead that participant's team and the participant must belong to this tournament, otherwise the field is null for every agent." } ], "responses": { "200": { "description": "The tournament free-agent pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentFreeAgentsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agents/{freeAgentId}/offers": { "post": { "operationId": "sendTournamentFreeAgentOffer", "tags": [ "Tournament Free Agency" ], "summary": "Offer to pick up a free agent", "description": "Sends a pickup offer from one of YOUR teams to a free agent listed in the tournament's pool. Nothing is rostered by this call - it creates a PENDING offer that the agent accepts or declines via POST /tournaments/{identifier}/free-agency/offers/{offerId}/respond.\n\nThe agent named by freeAgentId must currently be AVAILABLE, and the participant named in the body must be one of your teams and APPROVED in this tournament; you must be its captain, co-captain, or organization owner. Either condition failing answers 400 error_invalid_input or 403 respectively. An agent already rostered anywhere in this tournament cannot be offered to.\n\nRESENDING IS SAFE BUT NOT FREE. A live PENDING offer from the same team to the same agent answers 409 error_free_agent_offer_exists - revoke it first if you want to change the message. An offer that was previously declined, revoked, or expired is reused rather than duplicated, so a team and an agent never accumulate offer rows.\n\nBoth IDs must belong to the tournament in the path; either one from a different tournament answers 404 error_tournament_not_found, identically to one that does not exist. Requires the tournaments actor free_agency capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "freeAgentId", "schema": { "type": "string", "description": "Free-agent pool entry ID, as returned by GET /tournaments/{identifier}/free-agents." }, "required": true, "description": "Free-agent pool entry ID, as returned by GET /tournaments/{identifier}/free-agents." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentSendOfferBody" } } } }, "responses": { "200": { "description": "The offer was sent.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/free-agents/{freeAgentId}/remove": { "post": { "operationId": "removeTournamentFreeAgentFromPool", "tags": [ "Tournament: Free Agents" ], "summary": "Remove a free agent from the pool", "description": "Withdraws a free agent from the tournament pool as the organizer and expires their pending offers. Requires the tournaments free_agents capability and MANAGER authority - a tournament MODERATOR qualifies. ORDERING: an agent whose status is PICKED_UP is refused with 400 error_invalid_input (\"Remove the player from the team roster first\") and nothing is written, because withdrawing them while their FREE_AGENT roster entry survives would strand the player - no re-entry path accepts a non-AVAILABLE pool row, and the surviving roster entry keeps the re-pickup guards rejecting. Delete that roster entry first via DELETE /tournaments/{identifier}/roster-entries/{rosterEntryId}, which releases the agent back to AVAILABLE, then call this endpoint. An AVAILABLE agent can be removed directly.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "freeAgentId", "schema": { "type": "string", "description": "Tournament free-agent pool entry ID." }, "required": true, "description": "Tournament free-agent pool entry ID." } ], "responses": { "200": { "description": "The free agent was removed from the pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/invites": { "get": { "operationId": "listTournamentInvites", "tags": [ "Tournament: Staff & Invites" ], "summary": "List tournament team invites", "description": "Returns every team invite issued for the tournament, resolved by slug, in all four states. Re-inviting a team reuses that team's existing row rather than appending a new one, so there is exactly one invite per team and its `status` is the current state. Reading requires tournaments.tournament_admin:read on the key AND that the caller manages the tournament (host, tournament ADMIN, or tournament MODERATOR); sending and revoking invites requires ADMIN. Tournament API access is gated at api_pro on the tournament HOST OWNER's personal developer plan. An organization holding a consumer subscription does not satisfy this - the developer plan ladder has no organization arm.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "Tournament team invites.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentInvitesResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "createTournamentInvite", "tags": [ "Tournament: Staff & Invites" ], "summary": "Invite a team to a tournament", "description": "Invites a team to the tournament and notifies its captains. Requires the tournaments invites capability and ADMIN authority - strictly higher than the MANAGER floor for reading the invite list, because in an INVITE_ONLY tournament the invite is the entry gate; a tournament MODERATOR answers 403. Re-inviting a team reuses that team's existing invite row rather than creating a second one, so retries cannot mint duplicates. Answers 400 error_invalid_input when the team does not exist, plays a different game to the tournament, or already holds a PENDING or ACCEPTED invite.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentInviteTeamBody" } } } }, "responses": { "200": { "description": "The invite was created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/invites/{inviteId}/respond": { "post": { "operationId": "respondToTournamentInvite", "tags": [ "Tournament Entry" ], "summary": "Accept or decline a tournament invite", "description": "Answers an organizer's invite for a team you lead. The invite must still be PENDING; an already-answered or revoked invite answers 400 error_invalid_input.\n\nACCEPTING IS ENTRY, and carries entry's full refusal set. Supply roster - it is required whenever accept is true, and omitting it is rejected as an invalid request rather than silently failing later. The array must hold at least the tournament's teamSize active members of the invited team, or the request answers 400 error_roster_too_small. Acceptance also enforces the pre-start window (400 error_registration_closed), capacity (409 error_tournament_full), and one live entry per team (409 error_already_entered). On success the response carries the participantId, which is the handle for check-in and withdraw.\n\nDECLINING IS ALWAYS AVAILABLE. roster is ignored when accept is false, and the competitive-ban gate applies only to acceptance - a captain serving a ban can decline an invite so the organizer can move on, but receives 403 error_competitive_banned if they try to accept.\n\nAuthority comes from the invite: you must be the captain, co-captain, or organization owner of the invited team. An inviteId belonging to a different tournament answers 404 error_tournament_not_found. Invite IDs are returned by GET /tournaments/{identifier}/me. Requires the tournaments actor entry capability at read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "inviteId", "schema": { "type": "string", "description": "Tournament invite ID, as returned by GET /tournaments/{identifier}/me for a team you lead." }, "required": true, "description": "Tournament invite ID, as returned by GET /tournaments/{identifier}/me for a team you lead." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentInviteRespondBody" } } } }, "responses": { "200": { "description": "The response was recorded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentInviteRespondResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/invites/{inviteId}/revoke": { "post": { "operationId": "revokeTournamentInvite", "tags": [ "Tournament: Staff & Invites" ], "summary": "Revoke a tournament invite", "description": "Revokes a PENDING team invite. Requires the tournaments invites capability and ADMIN authority - the same floor as issuing one, because in an INVITE_ONLY tournament the invite is the entry gate; a tournament MODERATOR answers 403 but can still read the invite list. Answers 400 error_invalid_input when the invite is not pending: an already-accepted team is a participant, so remove them with the participant removal endpoint instead. No notification is sent - the invite simply disappears for the team.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "inviteId", "schema": { "type": "string", "description": "Tournament invite ID." }, "required": true, "description": "Tournament invite ID." } ], "responses": { "200": { "description": "The invite was revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/league-points": { "post": { "operationId": "setTournamentLeaguePoints", "tags": [ "Tournament: Lifecycle" ], "summary": "Configure tournament league points", "description": "Sets whether a league-hosted tournament awards league points on finalization, and the placement curve it awards them by. LEAGUE HOSTS ONLY - a tournament hosted by a user or an organization answers 400. Editable until the tournament finalizes; a COMPLETED or CANCELLED tournament answers 400. These two settings are NOT material fields, so this endpoint applies them directly and never routes them through re-approval, even on an approved tournament - that is exactly why they are not editable via the update endpoint. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentLeaguePointsRequestBody" } } } }, "responses": { "200": { "description": "The configuration was saved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentLeaguePointsResponse" } } } }, "400": { "description": "Bad request - includes a machine-readable placement-table reject reason.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentLeaguePointsRejected" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/me": { "get": { "operationId": "getMyTournamentEntry", "tags": [ "Tournament Entry" ], "summary": "Get your own state in a tournament", "description": "Returns the API key owner's own state in one tournament, resolved by slug: the teams they may act for, their teams' entries, invites addressed to those teams, free-agent offers addressed to them, the rosters they are personally on, and their free-agent pool row. Requires tournaments.actor.entry at read or read-write on the key; a read-only grant is enough, since this endpoint performs no writes.\n\nThis is the discovery endpoint for the competitor surface. Most competitor write endpoints are keyed by an opaque resource id - `participantId`, `inviteId`, `offerId`, `rosterEntryId` - that is returned here and nowhere else, so call this first.\n\nEvery collection is an ARRAY and is returned whole, including terminal rows: withdrawn, denied, removed and disqualified entries, responded invites, and expired, declined or revoked offers. A caller acting for several teams in one tournament has several entries and receives all of them. Do not assume at most one of anything.\n\nNo viewability filter is applied, because every field is already keyed to the caller. A tournament still in DRAFT that the caller has been invited to therefore answers 200, which is what makes the invite answerable before the tournament is published. A slug that does not resolve at all answers 404.\n\nUnlike the organizer endpoints this call is billed to the KEY OWNER rather than the tournament host, and is gated on the `writes` API feature (api_pro) rather than on the host's plan - a competitor's integration never depends on the organizer's billing.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The caller's state in the tournament.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MyTournamentEntryResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/nodes/{nodeId}/override-result": { "post": { "operationId": "overrideTournamentNodeResult", "tags": [ "Tournament: Bracket & Results" ], "summary": "Override a bracket node result", "description": "Applies an organizer-decided result to a bracket node and advances the bracket. Requires the tournaments bracket capability and ADMIN authority on the tournament - a tournament MODERATOR answers 403. The result must be decisive: the scores may not be equal, and one side must reach the node's winsNeeded (ceil(bestOf / 2)); a winning score above winsNeeded is accepted. Answers 400 error_invalid_input when the node is not READY or IN_PROGRESS, when either entrant is missing or disqualified, when the linked match has already started, or when the scores are not a decisive pair of non-negative integers.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "nodeId", "schema": { "type": "string", "description": "Bracket node ID." }, "required": true, "description": "Bracket node ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentOverrideNodeResultBody" } } } }, "responses": { "200": { "description": "The result was applied and the bracket advanced.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/nodes/{nodeId}/revert-result": { "post": { "operationId": "revertTournamentNodeResult", "tags": [ "Tournament: Bracket & Results" ], "summary": "Revert a bracket node result", "description": "Reverts an applied result on a COMPLETED or WALKOVER node and rolls the bracket back to it, cancelling the unplayed downstream matches the result created. The cascade policy is SHALLOW: answers 409 error_revert_blocked_downstream if any node the result fed has already been played, so revert a chain from its tip inwards. Answers 400 error_invalid_input when the tournament is not IN_PROGRESS, when the node has no applied result, or when a later swiss round has already been paired. `regenerateMatch` defaults to true. Requires the tournaments bracket capability and ADMIN authority - a tournament MODERATOR answers 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "nodeId", "schema": { "type": "string", "description": "Bracket node ID." }, "required": true, "description": "Bracket node ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRevertNodeResultBody" } } } }, "responses": { "200": { "description": "The result was reverted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants": { "get": { "operationId": "listTournamentParticipants", "tags": [ "Tournament Discovery" ], "summary": "List tournament participants", "description": "Returns every participating team with its tournament roster, resolved by slug. Includes pending, approved, withdrawn, and disqualified entries - filter on `status` for the active field. A tournament you may not view answers 404. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The tournament participants.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentParticipantsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants/{participantId}/check-in": { "post": { "operationId": "checkInToTournament", "tags": [ "Tournament Entry" ], "summary": "Check a team in for a tournament", "description": "Confirms that a team you lead is present for a tournament that is about to start. The participant must be APPROVED; a PENDING application or a withdrawn, removed, or disqualified row answers 400 error_invalid_input.\n\nSAFE TO RETRY. This endpoint is idempotent by effect: calling it again re-stamps the check-in timestamp and answers 200. There is no 'already checked in' conflict response, so a retry after a dropped connection is always safe. The consequence is that checkedInAt is the time of your LAST successful call, not your first - read it back from GET /tournaments/{identifier}/me rather than assuming it is stable.\n\nThe check-in window opens checkInOpensMinutesBefore minutes ahead of startsAt; outside it the request answers 400 error_check_in_closed. When the tournament has checkInRequired set to false there is no window and the call simply succeeds, so an integration can call this unconditionally without first branching on the flag.\n\nAuthority comes from the participant: you must be the captain, co-captain, or organization owner of the team it belongs to. A participantId from a different tournament answers 404 error_tournament_not_found. Requires the tournaments actor check_in capability - a narrower grant than entry, and deliberately not covered by it.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "responses": { "200": { "description": "The team is checked in.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants/{participantId}/disqualify": { "post": { "operationId": "disqualifyTournamentParticipant", "tags": [ "Tournament: Registration" ], "summary": "Disqualify a tournament participant", "description": "Disqualifies a participant and propagates the result through a running bracket: the opponent advances by walkover and the disqualified team's linked matches are terminated. Re-read the bracket afterwards rather than assuming the previous shape, and do not assume a fixed walkover score - the applied scoreline depends on the node's format and any head start. The team's outbound free-agent offers are expired and its picked-up free agents are released. `reason` is required and is quoted to the disqualified captain. Requires the tournaments registration capability and MANAGER authority - a tournament MODERATOR qualifies.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentDisqualifyParticipantBody" } } } }, "responses": { "200": { "description": "The participant was disqualified.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants/{participantId}/remove": { "post": { "operationId": "removeTournamentParticipant", "tags": [ "Tournament: Registration" ], "summary": "Remove a tournament participant", "description": "Sets the participant to REMOVED, decrementing the participant count if the team was APPROVED. Side effects a client should expect: the team's outbound free-agent offers are expired and the free agents it had picked up are released back to the pool. Unlike disqualification this does NOT propagate through a live bracket. Requires the tournaments registration capability and MANAGER authority on the tournament - a tournament MODERATOR qualifies.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRemoveParticipantBody" } } } }, "responses": { "200": { "description": "The participant was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants/{participantId}/roster": { "post": { "operationId": "addTournamentRosterMemberAsOrganizer", "tags": [ "Tournament: Registration" ], "summary": "Add a member to any participant's roster (organizer)", "description": "Adds a user to the named participant's tournament roster as the organizer. Requires ADMIN authority on the tournament - a tournament MODERATOR is NOT sufficient here, because editing any participant's roster carries the same weight as issuing an invite; a moderator edits only rosters for teams they lead, via the competitor roster endpoint. Answers 400 error_invalid_input when the user is not an active member of that team or is already rostered in this tournament. Requires the tournaments registration capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentOrganizerRosterAddBody" } } } }, "responses": { "200": { "description": "The member was added to the roster.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/participants/{participantId}/withdraw": { "post": { "operationId": "withdrawFromTournament", "tags": [ "Tournament Entry" ], "summary": "Withdraw your team from a tournament", "description": "Withdraws a team you lead from a tournament, setting its participant row to WITHDRAWN. Works from either PENDING (a pending application) or APPROVED (a confirmed entry); anything else answers 400 error_invalid_input because there is nothing to withdraw.\n\nThis is NOT a pure status flip - two side effects change state a client may be holding. The team's outbound free-agent offers are all expired, and every free agent it had picked up is released back to the pool and dropped from its tournament roster. Re-read GET /tournaments/{identifier}/me afterwards rather than patching a cached entry.\n\nAuthority is derived from the participant, not from the URL's tournament: you must be the captain, co-captain, or organization owner of the team that participant belongs to, and a participantId belonging to a team you do not lead answers 403. A participantId belonging to a different tournament answers 404 error_tournament_not_found, identically to one that does not exist.\n\nThe organizer's counterpart is POST /tournaments/{identifier}/participants/{participantId}/remove, which requires manager authority on the tournament. Requires the tournaments actor entry capability at read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "participantId", "schema": { "type": "string", "description": "Tournament participant ID." }, "required": true, "description": "Tournament participant ID." } ], "responses": { "200": { "description": "The team is withdrawn.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/regenerate-matches": { "post": { "operationId": "regenerateTournamentMatches", "tags": [ "Tournament: Lifecycle" ], "summary": "Regenerate tournament matches", "description": "Recovery lever for an IN_PROGRESS tournament whose match generation partially failed - typically after `POST /tournaments/{identifier}/start`, whose background chain gives each node one attempt before moving on. This starts a FRESH generation pass with an empty skip list, so every currently-eligible node is re-attempted. It is safe to call repeatedly: generation is exactly-once per node, so a node that already has a match is never regenerated and existing matches are never destroyed. A tournament that is not IN_PROGRESS answers 400. The work is ASYNCHRONOUS - `queued` is an upper bound on what will be re-attempted, not a completion count; poll `GET /tournaments/{identifier}/bracket` for the real state. Requires a SEPARATE `regenerate` capability on the key (it is not covered by `lifecycle`), and the key owner must be a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRegenerateMatchesRequestBody" } } } }, "responses": { "200": { "description": "Regeneration was scheduled (or there was nothing eligible).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRegenerateMatchesResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/registration/close": { "post": { "operationId": "closeTournamentRegistration", "tags": [ "Tournament: Lifecycle" ], "summary": "Close tournament registration", "description": "Moves a REGISTRATION_OPEN tournament to REGISTRATION_CLOSED. Takes no request body. Any other status answers 400. This is REVERSIBLE - registration can be re-opened from REGISTRATION_CLOSED. Unlike opening, closing emits NO webhook and does not change the tournament's public listing, so a webhook consumer will not observe this transition; poll the tournament if you need to react to it. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "Registration is closed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCloseRegistrationResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/registration/open": { "post": { "operationId": "openTournamentRegistration", "tags": [ "Tournament: Lifecycle" ], "summary": "Open tournament registration", "description": "Moves an APPROVED tournament to REGISTRATION_OPEN. Takes no request body. Registration can only be opened from DRAFT or REGISTRATION_CLOSED; any other status answers 400. A tournament that is not APPROVED answers 403 error_approval_required. Side effects worth knowing about: a PUBLIC tournament becomes publicly listed, a `tournament.registration_opened` webhook is emitted, and when check-in is required and a start time is set the check-in announcement is scheduled. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "Registration is open.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentOpenRegistrationResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/roster-entries/{rosterEntryId}": { "delete": { "operationId": "removeTournamentRosterEntryAsOrganizer", "tags": [ "Tournament: Registration" ], "summary": "Remove a roster entry from any participant (organizer)", "description": "Deletes one tournament roster entry as the organizer. Requires ADMIN authority on the tournament - a tournament MODERATOR is NOT sufficient; a moderator edits only rosters for teams they lead, via the competitor roster endpoint. If the entry was a picked-up free agent, that player is returned to the pool as AVAILABLE - which is the step that must precede removing them from the pool entirely. Answers 400 error_invalid_input when the entry does not exist. Requires the tournaments registration capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "rosterEntryId", "schema": { "type": "string", "description": "Tournament roster entry ID." }, "required": true, "description": "Tournament roster entry ID." } ], "responses": { "200": { "description": "The roster entry was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/rounds/{roundId}/schedule": { "post": { "operationId": "setTournamentRoundSchedule", "tags": [ "Tournament: Lifecycle" ], "summary": "Schedule a tournament round", "description": "Sets or clears the start time of a single round. A COMPLETED round answers 400, and a round that does not belong to the tournament in the path answers 404 error_tournament_not_found - identical to an unknown slug, so the endpoint is not an existence oracle. IMPORTANT: matches that have ALREADY been generated keep the start time they were generated with; the round's `startsAt` is a generation-time snapshot, so this only affects matches generated after the change. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "roundId", "schema": { "type": "string", "description": "Tournament round id." }, "required": true, "description": "Tournament round id." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRoundScheduleRequestBody" } } } }, "responses": { "200": { "description": "The round schedule was updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentRoundScheduleResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/staff": { "get": { "operationId": "listTournamentStaff", "tags": [ "Tournament: Staff & Invites" ], "summary": "List tournament staff", "description": "Returns the tournament's delegated staff, resolved by slug. The host is not included - host authority comes from the host record rather than a staff row, so an empty list means no delegated staff, not no organizers. Reading requires tournaments.tournament_admin:read on the key AND that the caller manages the tournament (host, tournament ADMIN, or tournament MODERATOR); adding and removing staff requires ADMIN. Tournament API access is gated at api_pro on the tournament HOST OWNER's personal developer plan. An organization holding a consumer subscription does not satisfy this - the developer plan ladder has no organization arm.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The tournament staff roster.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentStaffResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "addTournamentStaff", "tags": [ "Tournament: Staff & Invites" ], "summary": "Add or update a tournament staff member", "description": "Grants a user the ADMIN or MODERATOR staff role on the tournament. Requires the tournaments staff capability and ADMIN authority - strictly higher than the MANAGER floor for reading the roster, so a tournament MODERATOR answers 403 and cannot promote themselves. Upserts by user: posting a role for someone who already holds a staff row updates that row instead of creating a second one, so this endpoint is safely retryable and also serves as the change-role operation. A MODERATOR gains the manager-floor endpoints (application review, participant removal and disqualification, free-agent pool moderation) but none of the admin-floor ones.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentAddStaffBody" } } } }, "responses": { "200": { "description": "The staff member was added or their role updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/staff/{userId}": { "delete": { "operationId": "removeTournamentStaff", "tags": [ "Tournament: Staff & Invites" ], "summary": "Remove a tournament staff member", "description": "Removes the delegated staff row for the named user. Requires the tournaments staff capability and ADMIN authority on the tournament - a tournament MODERATOR answers 403, so a moderator cannot remove a peer. Idempotent: removing a user who holds no staff row succeeds, so a retry after a lost response is safe. Removing the host has no effect, because host authority comes from the host record rather than a staff row.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "userId", "schema": { "type": "string", "description": "User ID of the staff member to remove." }, "required": true, "description": "User ID of the staff member to remove." } ], "responses": { "200": { "description": "The staff member was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/start": { "post": { "operationId": "startTournament", "tags": [ "Tournament: Lifecycle" ], "summary": "Start a tournament", "description": "Seeds the participants, generates the bracket structure and moves the tournament to IN_PROGRESS. ASYNCHRONOUS: this answers 202 and RETURNS BEFORE ANY MATCH EXISTS. The actual matches are generated by a background scheduler chain that runs after the response, and that chain can partially fail - it gives a node ONE attempt and then moves on, so a 202 is not a promise that every match will appear. Poll `GET /tournaments/{identifier}/bracket` to observe real matches, and use `POST /tournaments/{identifier}/regenerate-matches` to re-attempt any that are missing. Preconditions: the tournament must be APPROVED and in REGISTRATION_OPEN or REGISTRATION_CLOSED, otherwise 403 error_approval_required or 400. WARNING - when check-in is required, starting REMOVES every approved participant who has not checked in, and the run is then rejected with 400 if fewer than `minParticipants` remain (the removals are rolled back with it). Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentStartRequestBody" } } } }, "responses": { "202": { "description": "The tournament started and the bracket was created. Match generation is still in flight - poll the bracket.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentStartResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/submit-for-approval": { "post": { "operationId": "submitTournamentForApproval", "tags": [ "Tournament: Lifecycle" ], "summary": "Submit a tournament for approval", "description": "Submits a DRAFT tournament for platform review. Takes no request body. Hosting eligibility is re-checked at submit time and answers 403 error_not_eligible_to_host when the key owner may no longer host. A tournament already AWAITING_APPROVAL answers 409 error_approval_pending, and a tournament that is not a DRAFT answers 400. Note the auto-approval shortcut: while the platform approval mode is `public_listing_only`, an UNLISTED tournament is approved immediately and `autoApproved` is true. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "responses": { "200": { "description": "The tournament was submitted (or auto-approved).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentSubmitForApprovalResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/teams/{teamIdentifier}/apply": { "post": { "operationId": "applyToTournament", "tags": [ "Tournament Entry" ], "summary": "Apply to a tournament as a team you lead", "description": "Submits an application for a team you lead to an APPLICATION-registration tournament and returns its participant ID. The participant is created PENDING and does NOT consume a slot, so unlike direct entry this endpoint never answers error_tournament_full - the capacity check happens when the organizer approves, and applying to a nominally full tournament is legitimate because approvals free slots. Use the sibling enter endpoint for OPEN-mode tournaments; a mode mismatch answers 400 error_invalid_input. Other refusals: 400 error_registration_closed outside the registration window, 400 error_roster_too_small below the tournament's teamSize, 409 error_already_entered when the team holds a non-terminal entry, and 403 error_competitive_banned while you are serving a competitive ban. There is no teamId body field - the acting team is the path segment. Requires the tournaments actor entry capability at read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "teamIdentifier", "schema": { "type": "string", "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." }, "required": true, "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentTeamEntryBody" } } } }, "responses": { "200": { "description": "The application was submitted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentTeamEntryResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/teams/{teamIdentifier}/enter": { "post": { "operationId": "enterTournament", "tags": [ "Tournament Entry" ], "summary": "Enter a tournament as a team you lead", "description": "Registers a team you lead directly into an OPEN-registration tournament and returns its participant ID. The entry is immediately APPROVED and consumes a participant slot, so the request is rejected with 409 error_tournament_full at capacity. Use the sibling apply endpoint for APPLICATION-mode tournaments - a mode mismatch answers 400 error_invalid_input rather than silently doing the other thing. Other refusals: 400 error_registration_closed outside the registration window, 400 error_roster_too_small below the tournament's teamSize, 409 error_already_entered when the team holds a non-terminal entry, and 403 error_competitive_banned while you are serving a competitive ban. There is no teamId body field - the acting team is the path segment, which is the only channel the leadership check covers. Requires the tournaments actor entry capability at read-write.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "teamIdentifier", "schema": { "type": "string", "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." }, "required": true, "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentTeamEntryBody" } } } }, "responses": { "200": { "description": "The team is entered.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentTeamEntryResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/teams/{teamIdentifier}/roster": { "post": { "operationId": "addTournamentRosterMemberAsTeam", "tags": [ "Tournament Entry" ], "summary": "Add a member to your own team's roster", "description": "Adds a user to the tournament roster of a team you lead. The participant edited is derived from the team in the path, so this endpoint can only ever touch your own team's roster - editing another participant's roster is the separate organizer endpoint and requires ADMIN authority over the tournament. Answers 400 error_invalid_input when the team is not entered in this tournament, when the user is not an ACTIVE member of that team, or when the user is already rostered in this tournament (one roster entry per user per tournament, across all teams). Requires the tournaments actor roster capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "teamIdentifier", "schema": { "type": "string", "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." }, "required": true, "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentTeamRosterAddBody" } } } }, "responses": { "200": { "description": "The member was added to the roster.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/teams/{teamIdentifier}/roster/{rosterEntryId}": { "delete": { "operationId": "removeTournamentRosterMemberAsTeam", "tags": [ "Tournament Entry" ], "summary": "Remove a member from your own team's roster", "description": "Removes a roster entry from a team you lead. The entry must belong to BOTH the tournament and the team in the path; an entry from another tournament or another team answers 404 error_tournament_not_found, identically to one that does not exist, so this endpoint is not a cross-team existence oracle. Roster entry IDs come from GET /tournaments/{identifier}/me for your own entry, or from the participants endpoint for the rest of your team. Removing an entry sourced from the free-agent pool releases that player back to the pool as AVAILABLE - the step that must precede removing a picked-up agent from the pool. Requires the tournaments actor roster capability.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." }, { "in": "path", "name": "teamIdentifier", "schema": { "type": "string", "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." }, "required": true, "description": "Slug of the team to act as. You must be its captain, co-captain, or the owner of the organization that owns it. A team you do not lead and a slug that does not resolve BOTH answer 403 error_not_team_leader, so that this path is not a team-slug enumeration oracle." }, { "in": "path", "name": "rosterEntryId", "schema": { "type": "string", "description": "Tournament roster entry ID." }, "required": true, "description": "Tournament roster entry ID." } ], "responses": { "200": { "description": "The roster entry was removed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentWriteAck" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/{identifier}/update": { "post": { "operationId": "updateTournament", "tags": [ "Tournament: Lifecycle" ], "summary": "Update a tournament", "description": "Applies a partial edit to a tournament, resolved by slug. The result is TRI-STATE and you must branch on `applied`: before the tournament has ever been approved the edit applies directly (`direct`); afterwards a material change is staged into a pending set and the tournament flips to AWAITING_APPROVAL (`pending`), and an edit that changes nothing is a `noop`. A COMPLETED or CANCELLED tournament rejects every edit with 400. Requires an API key holding the tournaments lifecycle capability whose owner is a tournament ADMIN - a tournamentStaff MODERATOR is NOT sufficient and receives 403.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Tournament slug." }, "required": true, "description": "Tournament slug." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentUpdateRequestBody" } } } }, "responses": { "200": { "description": "The edit was accepted. Branch on `applied`.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentUpdateResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tournaments/discover": { "post": { "operationId": "discoverTournaments", "tags": [ "Tournament Discovery" ], "summary": "Discover public tournaments", "description": "Returns publicly listed tournaments, featured entries first. Unlisted and draft tournaments are never included, whoever asks. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentDiscoverBody" } } } }, "responses": { "200": { "description": "A page of publicly listed tournaments.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentDiscoverPage" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/twitch/badges/channel": { "get": { "operationId": "getChannelTwitchBadges", "tags": [ "Twitch" ], "summary": "Get channel-specific Twitch chat badges", "description": "Returns a Twitch channel's chat badge sets. Provide exactly one of the username or id query parameters. The API key owner must have a linked Twitch connection. Requires the connections.twitch permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "username", "schema": { "description": "Channel login name (e.g. ninja). Provide exactly one of username or id.", "type": "string" }, "description": "Channel login name (e.g. ninja). Provide exactly one of username or id." }, { "in": "query", "name": "id", "schema": { "description": "Broadcaster id (e.g. 123456789). Provide exactly one of username or id.", "type": "string" }, "description": "Broadcaster id (e.g. 123456789). Provide exactly one of username or id." } ], "responses": { "200": { "description": "Channel-specific Twitch chat badge sets.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwitchChannelBadges" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/twitch/badges/global": { "get": { "operationId": "getGlobalTwitchBadges", "tags": [ "Twitch" ], "summary": "Get global Twitch chat badges", "description": "Returns Twitch's global chat badge sets. The API key owner must have a linked Twitch connection. Requires the connections.twitch permission.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "Global Twitch chat badge sets.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwitchGlobalBadges" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/uploads/image-url": { "post": { "operationId": "createImageUploadUrl", "tags": [ "Uploads" ], "summary": "Mint an image upload URL", "description": "Returns a short-lived, single-use Convex storage upload URL for the API key owner. POST the image bytes to the returned URL to receive a storageId, then supply that storageId on a downstream write (e.g. a score-ingest screenshotStorageIds). The owner is always derived from the API key. Requires uploads.upload:read-write and the writes feature (api_pro).", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "A freshly minted upload URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageUploadUrlResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/connections": { "get": { "operationId": "listUserOwnConnections", "tags": [ "My Account" ], "summary": "List the API key owner's connections", "description": "Returns the full set of connections for the API key owner, including private connections and the owner-only isSelfReported and showOnProfile flags. The user is always derived from the API key. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "The API key owner's connections.", "content": { "application/json": { "schema": { "type": "object", "properties": { "connections": { "type": "array", "items": { "$ref": "#/components/schemas/ApiOwnConnection" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "connections", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing connections, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/game-ranks": { "get": { "operationId": "listUserGameRanks", "tags": [ "My Account" ], "summary": "List the API key owner's game ranks", "description": "Returns every game rank for the API key owner. The user is always derived from the API key. Requires game.ranks:read.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "The API key owner's game ranks.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameRankListResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "upsertUserGameRank", "tags": [ "My Account" ], "summary": "Upsert one of the API key owner's game ranks", "description": "Creates or overwrites the API key owner's rank for a single (gameId, mode) slot, forcing source to \"api\". The user is always derived from the API key. Requires game.ranks:read-write and the writes feature (api_pro).", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameRankUpsertBody" } } } }, "responses": { "200": { "description": "The game rank was created or updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameRankUpsertResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/game-ranks/{gameId}/{mode}": { "delete": { "operationId": "deleteUserGameRank", "tags": [ "My Account" ], "summary": "Delete one of the API key owner's game ranks", "description": "Deletes the API key owner's rank for a single (gameId, mode) slot. No-op when no such rank exists. The user is always derived from the API key. Requires game.ranks:read-write and the writes feature (api_pro).", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "gameId", "schema": { "type": "string", "description": "Game definition ID of the rank to delete." }, "required": true, "description": "Game definition ID of the rank to delete." }, { "in": "path", "name": "mode", "schema": { "type": "string", "description": "Game mode / playlist of the rank to delete." }, "required": true, "description": "Game mode / playlist of the rank to delete." } ], "responses": { "200": { "description": "The rank was deleted, or no matching rank existed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GameRankDeleteResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/matches": { "post": { "operationId": "listUserMatches", "tags": [ "My Matches" ], "summary": "List the authenticated user's matches", "description": "Returns matches the API key owner participates in, newest first, with cursor pagination. Requires the matches.user_matches:read permission.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MatchesRequestBody" } } } }, "responses": { "200": { "description": "Cursor-paginated result. continueCursor is non-null even when isDone is true.", "content": { "application/json": { "schema": { "type": "object", "properties": { "page": { "type": "array", "items": { "$ref": "#/components/schemas/UserMatch" } }, "isDone": { "type": "boolean" }, "continueCursor": { "type": "string" } }, "required": [ "page", "isDone", "continueCursor" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/ongoing-matches": { "get": { "operationId": "listUserOngoingMatches", "tags": [ "My Matches" ], "summary": "List the API key owner's ongoing matches", "description": "Returns published ACCEPTED, READY, and IN_PROGRESS matches for active teams the API key owner belongs to. The user is always derived from the API key. Requires matches.user_matches:read.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "Ongoing matches for the API key owner.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OngoingMatchesResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/tournaments": { "get": { "operationId": "listMyTournaments", "tags": [ "My Tournaments" ], "summary": "List the tournaments you manage", "description": "Returns the tournaments the API key owner hosts or holds tournament staff on, including drafts and unapproved ones. Ordered attention-first, then most recently updated, and capped at 100. Requires tournaments.tournament_admin:read - the public read scope is deliberately insufficient because this surface exposes unlisted tournaments.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "Tournaments the key owner can manage.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MyTournamentsResponse" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/user/tournaments/calendar": { "get": { "operationId": "listMyTournamentCalendar", "tags": [ "My Tournaments" ], "summary": "List your tournament calendar", "description": "Returns registration-deadline, check-in-opening, and tournament-start milestones for tournaments the API key owner's teams are entered in. Cancelled tournaments are omitted, and scheduled tournament matches are not included here - they surface through the match endpoints. Defaults to the next 30 days when no window is given. Requires tournaments.tournament_public:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "query", "name": "rangeStart", "schema": { "description": "Window start, ISO 8601. Defaults to the time of the request.", "type": "string" }, "description": "Window start, ISO 8601. Defaults to the time of the request." }, { "in": "query", "name": "rangeEnd", "schema": { "description": "Window end, ISO 8601. Defaults to 30 days after `rangeStart`.", "type": "string" }, "description": "Window end, ISO 8601. Defaults to 30 days after `rangeStart`." } ], "responses": { "200": { "description": "Tournament milestones in the applied window, ascending by time.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TournamentCalendarResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}": { "get": { "operationId": "getUserProfile", "tags": [ "Players" ], "summary": "Get a public user profile", "description": "Returns an API-safe user profile projection. Private profiles return only the base profile envelope. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User profile.", "content": { "application/json": { "schema": { "type": "object", "properties": { "user": { "$ref": "#/components/schemas/ApiUserProfile" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "user", "timestamp" ], "additionalProperties": false, "description": "Envelope containing user plus a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/connections": { "get": { "operationId": "listUserConnections", "tags": [ "Players" ], "summary": "List public user connections", "description": "Returns a user's linked-account connections. Access requires a public profile or self: a non-self viewer of a limited or private profile gets 403, which is stricter than the stats, teams, and organizations endpoints that also allow limited profiles. Non-self responses include only the connections the user marked visible on their profile; self responses include all of them. isVerified is true when the connection's platform matches one of the user's linked OAuth providers, not the connection's self-reported flag. Not paginated: returns the full matching set as connections plus a count, in no guaranteed order. Banned users return 404. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User connections.", "content": { "application/json": { "schema": { "type": "object", "properties": { "connections": { "type": "array", "items": { "$ref": "#/components/schemas/ApiUserConnection" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "connections", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing connections, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/organizations": { "get": { "operationId": "listUserOrganizations", "tags": [ "Players" ], "summary": "List a user's organization affiliations", "description": "Returns the target user's active organization memberships, each as an API-safe organization summary plus the membership role and joinedAt. The identifier is a username or Convex user ID. Requires the users.profile:read scope. Readable only for public or limited profiles (or the API key owner's own profile); a private profile returns 403, and an unknown or banned user returns 404. For anyone other than the profile owner, only organizations whose profile visibility is public are returned; the owner sees all of their memberships (regardless of profile visibility or discovery). Note this gates on the organization's profile-visibility axis, not the separate paid public-discovery flag. Not paginated - the full set is returned with a count, in no guaranteed order (not sorted by name or joinedAt).", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User organization affiliations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "organizations": { "type": "array", "items": { "$ref": "#/components/schemas/ApiUserOrganizationMembership" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "organizations", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing organizations, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/stats": { "get": { "operationId": "getUserStats", "tags": [ "Players" ], "summary": "Get user aggregate stats", "description": "Returns aggregate user stats for public or limited profiles, plus self. Private non-self profiles return 403. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User stats.", "content": { "application/json": { "schema": { "type": "object", "properties": { "stats": { "$ref": "#/components/schemas/ApiUserStats" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "stats", "timestamp" ], "additionalProperties": false, "description": "Envelope containing stats plus a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/stream": { "get": { "operationId": "getUserStreamStatus", "tags": [ "Streaming" ], "summary": "Get a user's live-stream status", "description": "Returns whether a user is live, the platforms they are live on, and their primary (highest-viewer) stream details. The {identifier} may be a username or a Convex user ID. Visible for public or limited profiles, plus self; a private non-self profile returns 403. Unknown or currently-banned users return 404 (a banned user's existence is not leaked). When offline, isLive is false, platforms is empty, and primaryStream is null. Requires stream.read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "The user's live-stream status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiStreamStatusEnvelope" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/teams": { "get": { "operationId": "listUserTeams", "tags": [ "Players" ], "summary": "List user team affiliations", "description": "Returns the user's active team memberships as a non-paginated list with a count and response timestamp - there is no cursor, limit, or sort parameter, and rows come back in storage order. Each row is an API-safe team summary plus the membership role, joinedAt, and the team's parent organization (null when the team has no organization). Only active memberships are included. Requires the target profile to be public or limited (a private profile returns 403); the requester always sees their own affiliations regardless of visibility. For any profile other than your own, only teams that belong to an organization with a public profile are returned - teams in a non-public-profile or organization-less context are omitted. Banned or unknown identifiers return 404. The identifier may be a username or a Convex user ID. Requires the users.profile:read scope.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User team affiliations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "teams": { "type": "array", "items": { "$ref": "#/components/schemas/ApiUserTeamMembership" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "teams", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing teams, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/{identifier}/trophies": { "get": { "operationId": "listUserTrophies", "tags": [ "Players" ], "summary": "List user trophies", "description": "Returns every trophy awarded to the user, sorted newest first by awardedAt, as an unpaginated list with a count (no cursor or limit). The identifier is a username or Convex user ID. Visible only when the target profile is effectively public, or when the profile belongs to the API key owner (self-view is always treated as public); a non-self limited or private profile returns 403. An unknown or banned user returns 404. Event linkage fields such as matchId and tournamentId are omitted. Requires users.profile:read.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "identifier", "schema": { "type": "string", "description": "Username or Convex user ID." }, "required": true, "description": "Username or Convex user ID." } ], "responses": { "200": { "description": "User trophies.", "content": { "application/json": { "schema": { "type": "object", "properties": { "trophies": { "type": "array", "items": { "$ref": "#/components/schemas/ApiUserTrophy" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "trophies", "count", "timestamp" ], "additionalProperties": false, "description": "Envelope containing trophies, count, and a response timestamp." } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks": { "get": { "operationId": "listWebhooks", "tags": [ "Webhooks" ], "summary": "List webhook endpoints", "description": "Lists your webhook endpoints: those in the API key's derived scope, plus any league-scoped endpoints you own. Secret material is never returned. Requires the webhooks.manage permission.", "security": [ { "ApiKeyAuth": [] } ], "responses": { "200": { "description": "The caller's webhook endpoints.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookListResponse" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "createWebhook", "tags": [ "Webhooks" ], "summary": "Create a webhook endpoint", "description": "Creates a webhook endpoint. By default it is bound to the API key's derived scope (a personal key scopes to your user, a developer-app key to its game). Pass `leagueId` to create a league-scoped endpoint instead: you must be a current ADMIN of that league, and the league owner's plan must include the webhooks feature. Returns the signing secret ONCE. Requires the webhooks.manage permission and the webhooks feature.", "security": [ { "ApiKeyAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookBody" } } } }, "responses": { "201": { "description": "The created endpoint's id and one-time signing secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookSecret" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}": { "delete": { "operationId": "deleteWebhook", "tags": [ "Webhooks" ], "summary": "Delete a webhook endpoint", "description": "Deletes a webhook endpoint in the caller's scope, cascading its delivery logs and rate-limit bucket. Requires the webhooks.manage permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." } ], "responses": { "200": { "description": "Deletion acknowledged.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookOk" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "get": { "operationId": "getWebhook", "tags": [ "Webhooks" ], "summary": "Get a webhook endpoint", "description": "Returns one webhook endpoint in the caller's scope (no secret material). A scope/owner mismatch is reported as 404. Requires the webhooks.manage permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." } ], "responses": { "200": { "description": "The requested webhook endpoint.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpoint" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "updateWebhook", "tags": [ "Webhooks" ], "summary": "Update a webhook endpoint", "description": "Partially updates a webhook endpoint in the caller's scope. Re-enabling or changing the URL resets the failure count. Requires the webhooks.manage permission; league-scoped endpoints additionally require current league ADMIN membership and the webhooks feature on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateWebhookBody" } } } }, "responses": { "200": { "description": "Update acknowledged.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookOk" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/deliveries": { "get": { "operationId": "listWebhookDeliveries", "tags": [ "Webhooks" ], "summary": "List a webhook endpoint's deliveries", "description": "Returns the endpoint's delivery log, newest first, with native cursor pagination. Pass limit (1-100) and cursor query params. Requires the webhooks.manage permission.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." }, { "in": "query", "name": "limit", "schema": { "description": "Page size 1-100 (default 25), enforced by the handler.", "type": "string" }, "description": "Page size 1-100 (default 25), enforced by the handler." }, { "in": "query", "name": "cursor", "schema": { "description": "Opaque continuation cursor from a prior page's continueCursor.", "type": "string" }, "description": "Opaque continuation cursor from a prior page's continueCursor." } ], "responses": { "200": { "description": "Cursor-paginated result. continueCursor is non-null even when isDone is true.", "content": { "application/json": { "schema": { "type": "object", "properties": { "page": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookDelivery" } }, "isDone": { "type": "boolean" }, "continueCursor": { "type": "string" } }, "required": [ "page", "isDone", "continueCursor" ], "additionalProperties": false } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/deliveries/{deliveryId}/replay": { "post": { "operationId": "replayWebhookDelivery", "tags": [ "Webhooks" ], "summary": "Replay a webhook delivery", "description": "Re-queues a dead-lettered delivery for a fresh attempt. Delivered, in-flight, or still-retrying (failed) deliveries cannot be replayed (409). Requires the webhooks.manage permission; league-scoped endpoints additionally require current league ADMIN membership and the webhooks feature on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." }, { "in": "path", "name": "deliveryId", "schema": { "type": "string", "description": "Delivery-log row id to replay." }, "required": true, "description": "Delivery-log row id to replay." } ], "responses": { "200": { "description": "Replay re-queued.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookReplayResult" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/rotate-secret": { "post": { "operationId": "rotateWebhookSecret", "tags": [ "Webhooks" ], "summary": "Rotate a webhook signing secret", "description": "Rotates the endpoint's signing secret. The previous secret keeps signing for a 24h grace window so consumers can update without missing deliveries. Returns the new secret ONCE. Requires the webhooks.manage permission; league-scoped endpoints additionally require current league ADMIN membership and the webhooks feature on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." } ], "responses": { "200": { "description": "The new one-time signing secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookSecret" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/test": { "post": { "operationId": "testWebhook", "tags": [ "Webhooks" ], "summary": "Send a test.ping to a webhook endpoint", "description": "Sends a single signed test.ping delivery (no retries) and logs it. Use it to verify your endpoint and signature handling. Requires the webhooks.manage permission; league-scoped endpoints additionally require current league ADMIN membership and the webhooks feature on the league owner's plan.", "security": [ { "ApiKeyAuth": [] } ], "parameters": [ { "in": "path", "name": "id", "schema": { "type": "string", "description": "Webhook endpoint id." }, "required": true, "description": "Webhook endpoint id." } ], "responses": { "200": { "description": "The test delivery outcome.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookTestResult" } } } }, "400": { "description": "Bad request (invalid body, cursor, limit, or date).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks the required permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } }, "webhooks": { "achievement.unlocked": { "post": { "operationId": "webhook_achievement_unlocked", "summary": "achievement.unlocked webhook delivery", "description": "Delivered to a registered endpoint when a achievement.unlocked event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "achievement.unlocked" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/AchievementUnlockedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for achievement.unlocked." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "chat.message_reported": { "post": { "operationId": "webhook_chat_message_reported", "summary": "chat.message_reported webhook delivery", "description": "Delivered to a registered endpoint when a chat.message_reported event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "chat.message_reported" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ChatMessageReportedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for chat.message_reported." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "custommap.scan_completed": { "post": { "operationId": "webhook_custommap_scan_completed", "summary": "custommap.scan_completed webhook delivery", "description": "Delivered to a registered endpoint when a custommap.scan_completed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "custommap.scan_completed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/CustomMapScanCompletedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for custommap.scan_completed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.announcement": { "post": { "operationId": "webhook_league_announcement", "summary": "league.announcement webhook delivery", "description": "Delivered to a registered endpoint when a league.announcement event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.announcement" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueAnnouncementPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.announcement." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.ban_revoked": { "post": { "operationId": "webhook_league_ban_revoked", "summary": "league.ban_revoked webhook delivery", "description": "Delivered to a registered endpoint when a league.ban_revoked event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.ban_revoked" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueBanRevokedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.ban_revoked." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.cooldown_cleared": { "post": { "operationId": "webhook_league_cooldown_cleared", "summary": "league.cooldown_cleared webhook delivery", "description": "Delivered to a registered endpoint when a league.cooldown_cleared event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.cooldown_cleared" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueCooldownClearedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.cooldown_cleared." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.cooldown_issued": { "post": { "operationId": "webhook_league_cooldown_issued", "summary": "league.cooldown_issued webhook delivery", "description": "Delivered to a registered endpoint when a league.cooldown_issued event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.cooldown_issued" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueCooldownIssuedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.cooldown_issued." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.created": { "post": { "operationId": "webhook_league_created", "summary": "league.created webhook delivery", "description": "Delivered to a registered endpoint when a league.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.display_rules_updated": { "post": { "operationId": "webhook_league_display_rules_updated", "summary": "league.display_rules_updated webhook delivery", "description": "Delivered to a registered endpoint when a league.display_rules_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.display_rules_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueDisplayRulesUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.display_rules_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.featured": { "post": { "operationId": "webhook_league_featured", "summary": "league.featured webhook delivery", "description": "Delivered to a registered endpoint when a league.featured event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.featured" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueFeaturedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.featured." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.game_added": { "post": { "operationId": "webhook_league_game_added", "summary": "league.game_added webhook delivery", "description": "Delivered to a registered endpoint when a league.game_added event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.game_added" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueGameAddedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.game_added." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.game_removed": { "post": { "operationId": "webhook_league_game_removed", "summary": "league.game_removed webhook delivery", "description": "Delivered to a registered endpoint when a league.game_removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.game_removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueGameRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.game_removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.game_toggled": { "post": { "operationId": "webhook_league_game_toggled", "summary": "league.game_toggled webhook delivery", "description": "Delivered to a registered endpoint when a league.game_toggled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.game_toggled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueGameToggledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.game_toggled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.ownership_transferred": { "post": { "operationId": "webhook_league_ownership_transferred", "summary": "league.ownership_transferred webhook delivery", "description": "Delivered to a registered endpoint when a league.ownership_transferred event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.ownership_transferred" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueOwnershipTransferredPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.ownership_transferred." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.penalty_issued": { "post": { "operationId": "webhook_league_penalty_issued", "summary": "league.penalty_issued webhook delivery", "description": "Delivered to a registered endpoint when a league.penalty_issued event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.penalty_issued" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeaguePenaltyIssuedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.penalty_issued." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.points_updated": { "post": { "operationId": "webhook_league_points_updated", "summary": "league.points_updated webhook delivery", "description": "Delivered to a registered endpoint when a league.points_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.points_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeaguePointsUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.points_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.rules_updated": { "post": { "operationId": "webhook_league_rules_updated", "summary": "league.rules_updated webhook delivery", "description": "Delivered to a registered endpoint when a league.rules_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.rules_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueRulesUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.rules_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.season_activated": { "post": { "operationId": "webhook_league_season_activated", "summary": "league.season_activated webhook delivery", "description": "Delivered to a registered endpoint when a league.season_activated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.season_activated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSeasonActivatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.season_activated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.season_completed": { "post": { "operationId": "webhook_league_season_completed", "summary": "league.season_completed webhook delivery", "description": "Delivered to a registered endpoint when a league.season_completed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.season_completed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSeasonCompletedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.season_completed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.season_created": { "post": { "operationId": "webhook_league_season_created", "summary": "league.season_created webhook delivery", "description": "Delivered to a registered endpoint when a league.season_created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.season_created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSeasonCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.season_created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.season_removed": { "post": { "operationId": "webhook_league_season_removed", "summary": "league.season_removed webhook delivery", "description": "Delivered to a registered endpoint when a league.season_removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.season_removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSeasonRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.season_removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.settings_updated": { "post": { "operationId": "webhook_league_settings_updated", "summary": "league.settings_updated webhook delivery", "description": "Delivered to a registered endpoint when a league.settings_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.settings_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSettingsUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.settings_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.shutdown": { "post": { "operationId": "webhook_league_shutdown", "summary": "league.shutdown webhook delivery", "description": "Delivered to a registered endpoint when a league.shutdown event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.shutdown" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueShutdownPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.shutdown." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.shutdown_requested": { "post": { "operationId": "webhook_league_shutdown_requested", "summary": "league.shutdown_requested webhook delivery", "description": "Delivered to a registered endpoint when a league.shutdown_requested event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.shutdown_requested" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueShutdownRequestedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.shutdown_requested." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.staff_invited": { "post": { "operationId": "webhook_league_staff_invited", "summary": "league.staff_invited webhook delivery", "description": "Delivered to a registered endpoint when a league.staff_invited event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.staff_invited" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueStaffInvitedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.staff_invited." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.staff_removed": { "post": { "operationId": "webhook_league_staff_removed", "summary": "league.staff_removed webhook delivery", "description": "Delivered to a registered endpoint when a league.staff_removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.staff_removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueStaffRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.staff_removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.staff_role_changed": { "post": { "operationId": "webhook_league_staff_role_changed", "summary": "league.staff_role_changed webhook delivery", "description": "Delivered to a registered endpoint when a league.staff_role_changed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.staff_role_changed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueStaffRoleChangedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.staff_role_changed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.standings_updated": { "post": { "operationId": "webhook_league_standings_updated", "summary": "league.standings_updated webhook delivery", "description": "Delivered to a registered endpoint when a league.standings_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.standings_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueStandingsUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.standings_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.suspended": { "post": { "operationId": "webhook_league_suspended", "summary": "league.suspended webhook delivery", "description": "Delivered to a registered endpoint when a league.suspended event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.suspended" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueSuspendedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.suspended." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.team_approved": { "post": { "operationId": "webhook_league_team_approved", "summary": "league.team_approved webhook delivery", "description": "Delivered to a registered endpoint when a league.team_approved event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.team_approved" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueTeamApprovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.team_approved." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.team_banned": { "post": { "operationId": "webhook_league_team_banned", "summary": "league.team_banned webhook delivery", "description": "Delivered to a registered endpoint when a league.team_banned event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.team_banned" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueTeamBannedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.team_banned." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.team_denied": { "post": { "operationId": "webhook_league_team_denied", "summary": "league.team_denied webhook delivery", "description": "Delivered to a registered endpoint when a league.team_denied event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.team_denied" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueTeamDeniedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.team_denied." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.team_removed": { "post": { "operationId": "webhook_league_team_removed", "summary": "league.team_removed webhook delivery", "description": "Delivered to a registered endpoint when a league.team_removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.team_removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueTeamRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.team_removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.unfeatured": { "post": { "operationId": "webhook_league_unfeatured", "summary": "league.unfeatured webhook delivery", "description": "Delivered to a registered endpoint when a league.unfeatured event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.unfeatured" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueUnfeaturedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.unfeatured." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.unsuspended": { "post": { "operationId": "webhook_league_unsuspended", "summary": "league.unsuspended webhook delivery", "description": "Delivered to a registered endpoint when a league.unsuspended event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.unsuspended" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueUnsuspendedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.unsuspended." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "league.verified": { "post": { "operationId": "webhook_league_verified", "summary": "league.verified webhook delivery", "description": "Delivered to a registered endpoint when a league.verified event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "league.verified" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/LeagueVerifiedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for league.verified." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.accepted": { "post": { "operationId": "webhook_match_accepted", "summary": "match.accepted webhook delivery", "description": "Delivered to a registered endpoint when a match.accepted event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.accepted" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchAcceptedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.accepted." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.cancelled": { "post": { "operationId": "webhook_match_cancelled", "summary": "match.cancelled webhook delivery", "description": "Delivered to a registered endpoint when a match.cancelled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.cancelled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchCancelledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.cancelled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.completed": { "post": { "operationId": "webhook_match_completed", "summary": "match.completed webhook delivery", "description": "Delivered to a registered endpoint when a match.completed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.completed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchCompletedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.completed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.created": { "post": { "operationId": "webhook_match_created", "summary": "match.created webhook delivery", "description": "Delivered to a registered endpoint when a match.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.forfeited": { "post": { "operationId": "webhook_match_forfeited", "summary": "match.forfeited webhook delivery", "description": "Delivered to a registered endpoint when a match.forfeited event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.forfeited" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchForfeitedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.forfeited." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.published": { "post": { "operationId": "webhook_match_published", "summary": "match.published webhook delivery", "description": "Delivered to a registered endpoint when a match.published event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.published" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchPublishedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.published." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.ready": { "post": { "operationId": "webhook_match_ready", "summary": "match.ready webhook delivery", "description": "Delivered to a registered endpoint when a match.ready event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.ready" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchReadyPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.ready." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "match.started": { "post": { "operationId": "webhook_match_started", "summary": "match.started webhook delivery", "description": "Delivered to a registered endpoint when a match.started event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "match.started" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/MatchStartedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for match.started." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.created": { "post": { "operationId": "webhook_organization_created", "summary": "organization.created webhook delivery", "description": "Delivered to a registered endpoint when a organization.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.disabled": { "post": { "operationId": "webhook_organization_disabled", "summary": "organization.disabled webhook delivery", "description": "Delivered to a registered endpoint when a organization.disabled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.disabled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationDisabledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.disabled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.enabled": { "post": { "operationId": "webhook_organization_enabled", "summary": "organization.enabled webhook delivery", "description": "Delivered to a registered endpoint when a organization.enabled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.enabled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationEnabledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.enabled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.member_added": { "post": { "operationId": "webhook_organization_member_added", "summary": "organization.member_added webhook delivery", "description": "Delivered to a registered endpoint when a organization.member_added event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.member_added" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationMemberAddedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.member_added." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.member_removed": { "post": { "operationId": "webhook_organization_member_removed", "summary": "organization.member_removed webhook delivery", "description": "Delivered to a registered endpoint when a organization.member_removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.member_removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationMemberRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.member_removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.member_role_changed": { "post": { "operationId": "webhook_organization_member_role_changed", "summary": "organization.member_role_changed webhook delivery", "description": "Delivered to a registered endpoint when a organization.member_role_changed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.member_role_changed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationMemberRoleChangedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.member_role_changed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.ownership_transferred": { "post": { "operationId": "webhook_organization_ownership_transferred", "summary": "organization.ownership_transferred webhook delivery", "description": "Delivered to a registered endpoint when a organization.ownership_transferred event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.ownership_transferred" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationOwnershipTransferredPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.ownership_transferred." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.removed": { "post": { "operationId": "webhook_organization_removed", "summary": "organization.removed webhook delivery", "description": "Delivered to a registered endpoint when a organization.removed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.removed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationRemovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.removed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.unbanned": { "post": { "operationId": "webhook_organization_unbanned", "summary": "organization.unbanned webhook delivery", "description": "Delivered to a registered endpoint when a organization.unbanned event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.unbanned" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationUnbannedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.unbanned." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.updated": { "post": { "operationId": "webhook_organization_updated", "summary": "organization.updated webhook delivery", "description": "Delivered to a registered endpoint when a organization.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "organization.user_banned": { "post": { "operationId": "webhook_organization_user_banned", "summary": "organization.user_banned webhook delivery", "description": "Delivered to a registered endpoint when a organization.user_banned event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "organization.user_banned" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/OrganizationUserBannedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for organization.user_banned." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "payment.failed": { "post": { "operationId": "webhook_payment_failed", "summary": "payment.failed webhook delivery", "description": "Delivered to a registered endpoint when a payment.failed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "payment.failed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/PaymentFailedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for payment.failed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "payment.refunded": { "post": { "operationId": "webhook_payment_refunded", "summary": "payment.refunded webhook delivery", "description": "Delivered to a registered endpoint when a payment.refunded event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "payment.refunded" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/PaymentRefundedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for payment.refunded." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "payment.succeeded": { "post": { "operationId": "webhook_payment_succeeded", "summary": "payment.succeeded webhook delivery", "description": "Delivered to a registered endpoint when a payment.succeeded event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "payment.succeeded" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/PaymentSucceededPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for payment.succeeded." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "player.checked_in": { "post": { "operationId": "webhook_player_checked_in", "summary": "player.checked_in webhook delivery", "description": "Delivered to a registered endpoint when a player.checked_in event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "player.checked_in" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/PlayerCheckedInPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for player.checked_in." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "player.stats_updated": { "post": { "operationId": "webhook_player_stats_updated", "summary": "player.stats_updated webhook delivery", "description": "Delivered to a registered endpoint when a player.stats_updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "player.stats_updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/PlayerStatsUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for player.stats_updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "rank.updated": { "post": { "operationId": "webhook_rank_updated", "summary": "rank.updated webhook delivery", "description": "Delivered to a registered endpoint when a rank.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "rank.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/RankUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for rank.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "referral.milestone": { "post": { "operationId": "webhook_referral_milestone", "summary": "referral.milestone webhook delivery", "description": "Delivered to a registered endpoint when a referral.milestone event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "referral.milestone" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ReferralMilestonePayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for referral.milestone." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "roster.updated": { "post": { "operationId": "webhook_roster_updated", "summary": "roster.updated webhook delivery", "description": "Delivered to a registered endpoint when a roster.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "roster.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/RosterUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for roster.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "score.confirmed": { "post": { "operationId": "webhook_score_confirmed", "summary": "score.confirmed webhook delivery", "description": "Delivered to a registered endpoint when a score.confirmed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "score.confirmed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ScoreConfirmedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for score.confirmed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "score.dispute_resolved": { "post": { "operationId": "webhook_score_dispute_resolved", "summary": "score.dispute_resolved webhook delivery", "description": "Delivered to a registered endpoint when a score.dispute_resolved event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "score.dispute_resolved" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ScoreDisputeResolvedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for score.dispute_resolved." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "score.disputed": { "post": { "operationId": "webhook_score_disputed", "summary": "score.disputed webhook delivery", "description": "Delivered to a registered endpoint when a score.disputed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "score.disputed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ScoreDisputedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for score.disputed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "score.submitted": { "post": { "operationId": "webhook_score_submitted", "summary": "score.submitted webhook delivery", "description": "Delivered to a registered endpoint when a score.submitted event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "score.submitted" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/ScoreSubmittedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for score.submitted." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "stream.offline": { "post": { "operationId": "webhook_stream_offline", "summary": "stream.offline webhook delivery", "description": "Delivered to a registered endpoint when a stream.offline event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "stream.offline" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/StreamOfflinePayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for stream.offline." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "stream.online": { "post": { "operationId": "webhook_stream_online", "summary": "stream.online webhook delivery", "description": "Delivered to a registered endpoint when a stream.online event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "stream.online" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/StreamOnlinePayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for stream.online." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "subscription.cancelled": { "post": { "operationId": "webhook_subscription_cancelled", "summary": "subscription.cancelled webhook delivery", "description": "Delivered to a registered endpoint when a subscription.cancelled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "subscription.cancelled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/SubscriptionCancelledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for subscription.cancelled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "subscription.created": { "post": { "operationId": "webhook_subscription_created", "summary": "subscription.created webhook delivery", "description": "Delivered to a registered endpoint when a subscription.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "subscription.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/SubscriptionCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for subscription.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "subscription.updated": { "post": { "operationId": "webhook_subscription_updated", "summary": "subscription.updated webhook delivery", "description": "Delivered to a registered endpoint when a subscription.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "subscription.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/SubscriptionUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for subscription.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.banned": { "post": { "operationId": "webhook_team_banned", "summary": "team.banned webhook delivery", "description": "Delivered to a registered endpoint when a team.banned event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.banned" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamBannedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.banned." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.created": { "post": { "operationId": "webhook_team_created", "summary": "team.created webhook delivery", "description": "Delivered to a registered endpoint when a team.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.disbanded": { "post": { "operationId": "webhook_team_disbanded", "summary": "team.disbanded webhook delivery", "description": "Delivered to a registered endpoint when a team.disbanded event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.disbanded" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamDisbandedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.disbanded." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.joined": { "post": { "operationId": "webhook_team_joined", "summary": "team.joined webhook delivery", "description": "Delivered to a registered endpoint when a team.joined event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.joined" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamJoinedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.joined." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.left": { "post": { "operationId": "webhook_team_left", "summary": "team.left webhook delivery", "description": "Delivered to a registered endpoint when a team.left event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.left" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamLeftPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.left." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.member_role_changed": { "post": { "operationId": "webhook_team_member_role_changed", "summary": "team.member_role_changed webhook delivery", "description": "Delivered to a registered endpoint when a team.member_role_changed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.member_role_changed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamMemberRoleChangedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.member_role_changed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "team.updated": { "post": { "operationId": "webhook_team_updated", "summary": "team.updated webhook delivery", "description": "Delivered to a registered endpoint when a team.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "team.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TeamUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for team.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "ticket.closed": { "post": { "operationId": "webhook_ticket_closed", "summary": "ticket.closed webhook delivery", "description": "Delivered to a registered endpoint when a ticket.closed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "ticket.closed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TicketClosedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for ticket.closed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "ticket.created": { "post": { "operationId": "webhook_ticket_created", "summary": "ticket.created webhook delivery", "description": "Delivered to a registered endpoint when a ticket.created event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "ticket.created" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TicketCreatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for ticket.created." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "ticket.reopened": { "post": { "operationId": "webhook_ticket_reopened", "summary": "ticket.reopened webhook delivery", "description": "Delivered to a registered endpoint when a ticket.reopened event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "ticket.reopened" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TicketReopenedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for ticket.reopened." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "ticket.updated": { "post": { "operationId": "webhook_ticket_updated", "summary": "ticket.updated webhook delivery", "description": "Delivered to a registered endpoint when a ticket.updated event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "ticket.updated" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TicketUpdatedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for ticket.updated." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.approved": { "post": { "operationId": "webhook_tournament_approved", "summary": "tournament.approved webhook delivery", "description": "Delivered to a registered endpoint when a tournament.approved event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.approved" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentApprovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.approved." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.cancelled": { "post": { "operationId": "webhook_tournament_cancelled", "summary": "tournament.cancelled webhook delivery", "description": "Delivered to a registered endpoint when a tournament.cancelled event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.cancelled" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentCancelledPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.cancelled." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.completed": { "post": { "operationId": "webhook_tournament_completed", "summary": "tournament.completed webhook delivery", "description": "Delivered to a registered endpoint when a tournament.completed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.completed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentCompletedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.completed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.featured": { "post": { "operationId": "webhook_tournament_featured", "summary": "tournament.featured webhook delivery", "description": "Delivered to a registered endpoint when a tournament.featured event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.featured" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentFeaturedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.featured." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.participant_approved": { "post": { "operationId": "webhook_tournament_participant_approved", "summary": "tournament.participant_approved webhook delivery", "description": "Delivered to a registered endpoint when a tournament.participant_approved event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.participant_approved" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentParticipantApprovedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.participant_approved." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.registration_opened": { "post": { "operationId": "webhook_tournament_registration_opened", "summary": "tournament.registration_opened webhook delivery", "description": "Delivered to a registered endpoint when a tournament.registration_opened event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.registration_opened" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentRegistrationOpenedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.registration_opened." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.round_completed": { "post": { "operationId": "webhook_tournament_round_completed", "summary": "tournament.round_completed webhook delivery", "description": "Delivered to a registered endpoint when a tournament.round_completed event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.round_completed" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentRoundCompletedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.round_completed." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.started": { "post": { "operationId": "webhook_tournament_started", "summary": "tournament.started webhook delivery", "description": "Delivered to a registered endpoint when a tournament.started event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.started" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentStartedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.started." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "tournament.unfeatured": { "post": { "operationId": "webhook_tournament_unfeatured", "summary": "tournament.unfeatured webhook delivery", "description": "Delivered to a registered endpoint when a tournament.unfeatured event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "tournament.unfeatured" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TournamentUnfeaturedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for tournament.unfeatured." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } }, "trophy.awarded": { "post": { "operationId": "webhook_trophy_awarded", "summary": "trophy.awarded webhook delivery", "description": "Delivered to a registered endpoint when a trophy.awarded event occurs.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "const": "trophy.awarded" }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "$ref": "#/components/schemas/TrophyAwardedPayload" } }, "required": [ "id", "event", "created_at", "data" ], "description": "Webhook envelope for trophy.awarded." } } } }, "responses": { "200": { "description": "Acknowledged. Return 2xx to mark the delivery successful." } } } } }, "components": { "schemas": { "ReportChatMessageRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional reason for the report (max 500 chars).", "type": "string", "maxLength": 500 } }, "description": "Reports a chat message for staff moderation review." }, "ListGameMatchesBody": { "type": "object", "properties": { "status": { "description": "Optional MatchStatus filter (e.g. IN_PROGRESS).", "type": "string" }, "limit": { "description": "Page size (1-100, enforced by the handler). Defaults to the handler's internal default.", "type": "number" }, "cursor": { "description": "Opaque continuation cursor from a prior page's pagination.cursor.", "type": "string" } }, "description": "Status filter and cursor pagination for listing the bound key's game matches. The game is derived from the developer-app key's bound game (not a body field)." }, "GameForfeitBody": { "type": "object", "properties": { "forfeitingTeamId": { "type": "string", "description": "ID of the team that forfeits. Must be a participant of the match." }, "reason": { "description": "Optional human-readable forfeit reason, recorded on the match.", "type": "string" } }, "required": [ "forfeitingTeamId" ], "description": "Request body for forfeiting a match on behalf of one participating team." }, "GamePlayerStatsBody": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Zero-based index of the map whose stats are being updated." }, "playerStats": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Per-player stats keyed by user ID. The map score must already exist." } }, "required": [ "mapIndex", "playerStats" ], "description": "Request body for submitting or updating player stats for an existing map score." }, "GameBatchScoresBody": { "type": "object", "properties": { "maps": { "minItems": 1, "type": "array", "items": { "$ref": "#/components/schemas/GameMapScoreInput" }, "description": "Map scores to submit. Must contain at least one entry." } }, "required": [ "maps" ], "description": "Request body for submitting one or more map scores in a single call." }, "GameMapScoreInput": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Zero-based index of the map within the series." }, "mapId": { "type": "string", "description": "Identifier of the map that was played." }, "creatorTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the creator team (integer, 0-1000)." }, "opponentTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the opponent (accepted) team (integer, 0-1000)." }, "screenshotUrls": { "description": "Optional external screenshot URLs supporting the reported score. Each must be a public https URL. Prefer screenshotStorageIds (validated blobs) where possible.", "type": "array", "items": { "type": "string" } }, "screenshotStorageIds": { "description": "Optional storage IDs for screenshots uploaded via POST /uploads/image-url. Preferred over screenshotUrls: each is validated (size, content-type, ownership) and resolved to a URL server-side.", "type": "array", "items": { "type": "string" } }, "playerStats": { "description": "Optional per-player stats keyed by user ID.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "mapIndex", "mapId", "creatorTeamScore", "opponentTeamScore" ], "description": "One map's score within a batch submission." }, "GameSingleMapScoreBody": { "type": "object", "properties": { "mapId": { "type": "string", "description": "Identifier of the map that was played." }, "creatorTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the creator team (integer, 0-1000)." }, "opponentTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the opponent (accepted) team (integer, 0-1000)." }, "screenshotUrls": { "description": "Optional external screenshot URLs supporting the reported score. Each must be a public https URL. Prefer screenshotStorageIds (validated blobs) where possible.", "type": "array", "items": { "type": "string" } }, "screenshotStorageIds": { "description": "Optional storage IDs for screenshots uploaded via POST /uploads/image-url. Preferred over screenshotUrls: each is validated (size, content-type, ownership) and resolved to a URL server-side.", "type": "array", "items": { "type": "string" } }, "playerStats": { "description": "Optional per-player stats keyed by user ID.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "mapId", "creatorTeamScore", "opponentTeamScore" ], "description": "Request body for submitting a single map's score (mapIndex comes from the path)." }, "GameStatusUpdateBody": { "type": "object", "properties": { "status": { "type": "string", "description": "Target status. Allowed transitions: READY -> IN_PROGRESS, IN_PROGRESS -> COMPLETED|CANCELLED, ACCEPTED -> CANCELLED. COMPLETED is not accepted directly (matches complete automatically once scores are confirmed)." } }, "required": [ "status" ], "description": "Request body for updating a match's lifecycle status." }, "GameBatchMatchScoresBody": { "type": "object", "properties": { "items": { "minItems": 1, "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/GameMultiMatchScoreItem" }, "description": "Map scores to submit across one or more matches. 1-50 entries." } }, "required": [ "items" ], "description": "Request body for submitting map scores across multiple matches in a single call (capped at 50 items)." }, "GameMultiMatchScoreItem": { "type": "object", "properties": { "matchId": { "type": "string", "description": "ID of the match this map score belongs to." }, "mapIndex": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Zero-based index of the map within the series." }, "mapId": { "type": "string", "description": "Identifier of the map that was played." }, "creatorTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the creator team (integer, 0-1000)." }, "opponentTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Score for the opponent (accepted) team (integer, 0-1000)." }, "screenshotUrls": { "description": "Optional external screenshot URLs supporting the reported score. Each must be a public https URL. Prefer screenshotStorageIds (validated blobs) where possible.", "type": "array", "items": { "type": "string" } }, "screenshotStorageIds": { "description": "Optional storage IDs for screenshots uploaded via POST /uploads/image-url. Preferred over screenshotUrls: each is validated (size, content-type, ownership) and resolved to a URL server-side.", "type": "array", "items": { "type": "string" } }, "playerStats": { "description": "Optional per-player stats keyed by user ID.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "matchId", "mapIndex", "mapId", "creatorTeamScore", "opponentTeamScore" ], "description": "One match's single map score within a multi-match batch submission." }, "GameCreateMatchBody": { "type": "object", "properties": { "creatorTeamId": { "type": "string", "description": "ID of the creating team. Must belong to the key's bound game." }, "acceptedTeamId": { "type": "string", "description": "ID of the opposing team. Required - game-originated matches are two-sided. Must belong to the key's bound game." }, "gameModeId": { "type": "string", "description": "Game mode identifier (e.g. search_and_destroy)." }, "bestOf": { "type": "number", "enum": [ 1, 3, 5, 7 ], "description": "Number of maps in the series. One of 1, 3, 5, or 7." }, "teamSize": { "type": "number", "description": "Players per team (validated against the game's min/max)." }, "platform": { "type": "string", "enum": [ "PC", "XBOX", "PLAYSTATION", "CONSOLE_ONLY", "CROSSPLAY" ], "description": "Match platform (e.g. CROSSPLAY)." }, "inputDevice": { "type": "string", "enum": [ "ALL", "CONTROLLER", "KB_M" ], "description": "Allowed input device (e.g. ALL)." }, "region": { "type": "string", "enum": [ "NONE", "NA_EAST", "NA_WEST", "EU", "ASIA", "OCEANIA", "SOUTH_AMERICA", "MIDDLE_EAST", "AFRICA" ], "description": "Match region (e.g. NONE)." }, "mapSelectionType": { "type": "string", "enum": [ "COMPETITIVE", "FLEX" ], "description": "Map selection type (COMPETITIVE or FLEX)." }, "mapPreferenceMode": { "type": "string", "enum": [ "PREFERRED", "VETO", "MANUAL" ], "description": "Map preference mode (PREFERRED, VETO, or MANUAL)." }, "selectedMaps": { "description": "Optional pre-selected map IDs.", "type": "array", "items": { "type": "string" } }, "selectedObjectives": { "description": "Optional pre-selected objective IDs.", "type": "array", "items": { "type": "string" } }, "scheduledAt": { "description": "Optional scheduled start time (epoch ms).", "type": "number" } }, "required": [ "creatorTeamId", "acceptedTeamId", "gameModeId", "bestOf", "teamSize", "platform", "inputDevice", "region", "mapSelectionType", "mapPreferenceMode" ], "description": "Request body for creating a two-sided game-originated match. The match is created ACCEPTED + PUBLISHED for the key's bound game. Supports an optional Idempotency-Key header for safe retries." }, "LeaderboardSortBy": { "type": "string", "enum": [ "wins", "winRate", "experience" ], "description": "Supported leaderboard sort field." }, "DiscoverLeaguesRequestBody": { "type": "object", "properties": { "search": { "description": "Free-text search across league names.", "type": "string" }, "gameId": { "description": "Filter to leagues that include this game id.", "type": "string" }, "page": { "default": 1, "description": "1-based page number. Defaults to 1.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "limit": { "default": 12, "description": "Page size (1-50). Defaults to 12.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "description": "Filters and offset pagination for discovering leagues." }, "LeagueActivityFeedRequestBody": { "type": "object", "properties": { "limit": { "default": 25, "type": "integer", "minimum": 1, "maximum": 100 }, "cursor": { "default": null, "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "description": "Cursor pagination options for a league activity feed." }, "AnnounceLeagueRequestBody": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "description": "Announcement title." }, "body": { "type": "string", "minLength": 1, "description": "Announcement body text." } }, "required": [ "title", "body" ], "description": "Sends an announcement to all members of the league." }, "LeagueApplyEligibilityRequestBody": { "type": "object", "properties": { "teamId": { "description": "Optional team ID to check. The API key owner must lead it.", "type": "string" } }, "description": "Optional team-specific league application eligibility selector." }, "BansRequestBody": { "type": "object", "properties": { "status": { "description": "Filter bans by computed status. Defaults to all.", "type": "string", "enum": [ "active", "expired", "revoked", "all" ] } }, "description": "Status filter for league team bans." }, "RevokeBanRequestBody": { "default": {}, "description": "Optional reason for revoking a league ban.", "type": "object", "properties": { "reason": { "description": "Optional revocation reason.", "type": "string", "maxLength": 500 } } }, "CreateBanRequestBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Team ID to ban from the league." }, "reason": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Reason for the ban." }, "isPermanent": { "type": "boolean", "description": "Whether the ban never expires." }, "expiresAt": { "description": "Expiration timestamp for temporary bans, in epoch milliseconds.", "type": "number" } }, "required": [ "teamId", "reason", "isPermanent" ], "description": "Creates a league team ban." }, "UpdateLeagueBrandingRequestBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 3, "maxLength": 50 }, "description": { "type": "string", "minLength": 10, "maxLength": 500 }, "avatarStorageId": { "description": "Convex storage ID for the league avatar.", "type": "string", "minLength": 1 }, "bannerStorageId": { "description": "Convex storage ID for the league banner.", "type": "string", "minLength": 1 }, "socials": { "$ref": "#/components/schemas/LeagueBrandingSocials" }, "profileThemeId": { "type": "string" } }, "description": "Updates league profile branding and public metadata." }, "LeagueBrandingSocials": { "type": "object", "properties": { "discord": { "type": "string" }, "twitter": { "type": "string" }, "youtube": { "type": "string" }, "twitch": { "type": "string" }, "website": { "type": "string" } } }, "UpdateLeagueCooldownConfigRequestBody": { "type": "object", "properties": { "selfLeaveCooldownHours": { "type": "number", "minimum": 0, "maximum": 8760 }, "kickCooldownHours": { "type": "number", "minimum": 0, "maximum": 8760 }, "repeatLeavePenaltyEnabled": { "type": "boolean" }, "repeatLeaveCooldownMultiplier": { "type": "number", "minimum": 1, "maximum": 10 }, "maxCooldownHours": { "type": "number", "minimum": 0, "maximum": 8760 } }, "description": "Updates league member cooldown configuration." }, "IssueCooldownRequestBody": { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1, "description": "User ID receiving the cooldown." }, "cooldownHours": { "type": "integer", "minimum": 1, "maximum": 8760, "description": "Cooldown length in hours, from 1 to 8760." }, "note": { "description": "Optional admin note.", "type": "string", "maxLength": 500 } }, "required": [ "userId", "cooldownHours" ], "description": "Issues or updates a manual league member cooldown." }, "LeagueDisplayRulesRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "description": "Game ID to list display rules for." } }, "required": [ "gameId" ], "description": "Display rule selector." }, "ReorderDisplayRulesRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID whose display rules should reorder." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Display rule ID." }, "order": { "type": "number" } }, "required": [ "id", "order" ] } } }, "required": [ "gameId", "items" ], "description": "Reorders display rules." }, "UpsertDisplayRuleRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID whose display rule should change." }, "category": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Display rule category." }, "scope": { "type": "object", "properties": { "modes": { "type": "array", "items": { "type": "string" } }, "playlists": { "type": "array", "items": { "type": "string" } } } }, "categoryIcon": { "type": "string" }, "categoryOrder": { "type": "number" }, "isCustomCategory": { "type": "boolean" }, "isOverride": { "type": "boolean" }, "content": { "type": "object", "properties": { "sections": { "type": "array", "items": { "type": "object", "properties": { "heading": { "type": "string" }, "items": { "type": "array", "items": { "type": "string" } } }, "required": [ "items" ] } } }, "required": [ "sections" ] } }, "required": [ "gameId", "category", "categoryOrder", "isCustomCategory", "isOverride", "content" ], "description": "Creates or updates a display rule." }, "ToggleLeagueGameRequestBody": { "type": "object", "properties": { "isActive": { "type": "boolean", "description": "Whether the game should be active." } }, "required": [ "isActive" ], "description": "Toggles a league game." }, "AddLeagueGameRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID to add to the league." } }, "required": [ "gameId" ], "description": "Adds a league game." }, "LeagueStatusUpdateBody": { "type": "object", "properties": { "status": { "type": "string", "description": "Target status. Allowed league transitions: READY -> IN_PROGRESS|CANCELLED, ACCEPTED -> CANCELLED. COMPLETED is not accepted directly; matches complete automatically once scores are confirmed." } }, "required": [ "status" ], "description": "Request body for updating a league match's lifecycle status." }, "UpdateLeagueMemberRoleRequestBody": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "ADMIN", "MANAGER", "MEMBER" ], "description": "Assignable league staff role. OWNER cannot be assigned through this API." } }, "required": [ "role" ], "description": "Updates a league staff member role." }, "AddLeagueMemberRequestBody": { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1, "description": "User ID to add to league staff." }, "role": { "type": "string", "enum": [ "ADMIN", "MANAGER", "MEMBER" ], "description": "Assignable league staff role. OWNER cannot be assigned through this API." } }, "required": [ "userId", "role" ], "description": "Adds or reactivates a league staff member." }, "TransferLeagueOwnershipRequestBody": { "type": "object", "properties": { "targetUserId": { "type": "string", "minLength": 1, "description": "User ID of the target league owner." } }, "required": [ "targetUserId" ], "description": "Transfers league ownership to an existing staff member." }, "PenaltiesRequestBody": { "type": "object", "properties": { "type": { "default": "all", "description": "Which record kinds to return. Defaults to all.", "type": "string", "enum": [ "penalties", "cooldowns", "all" ] }, "teamId": { "description": "Filter penalties to a specific team id.", "type": "string" }, "gameId": { "description": "Filter penalties to a specific game id.", "type": "string" }, "limit": { "default": 50, "description": "Maximum number of penalties to return (1-100). Defaults to 50.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "description": "Type, team, game, and limit filters for league penalties and cooldowns." }, "CreatePenaltyRequestBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Team ID receiving the penalty." }, "gameId": { "type": "string", "minLength": 1, "description": "Game ID for the league penalty." }, "seasonId": { "description": "Optional league season ID for the penalty.", "type": "string", "minLength": 1 }, "type": { "type": "string", "enum": [ "POINT_DEDUCTION", "MATCH_FORFEIT", "WARNING" ], "description": "Penalty type." }, "value": { "description": "Point value for POINT_DEDUCTION (integer, 1-1000).", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 }, "reason": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Reason for the penalty." } }, "required": [ "teamId", "gameId", "type", "reason" ], "description": "Creates a league team penalty." }, "UpdatePointsConfigRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID whose points config should change." }, "unitLabel": { "type": "string", "enum": [ "POINTS", "EXPERIENCE" ] }, "baseWin": { "type": "number" }, "baseLoss": { "type": "number" }, "baseDraw": { "type": "number" }, "allowNegative": { "type": "boolean" }, "streakBonusEnabled": { "type": "boolean" }, "streakBreakpoints": { "type": "array", "items": { "type": "object", "properties": { "count": { "type": "number" }, "bonus": { "type": "number" } }, "required": [ "count", "bonus" ] } }, "challengerWinBonus": { "type": "number" }, "challengedWinBonus": { "type": "number" }, "forfeitPenalty": { "type": "number" }, "challengeRefuseAdditionalPenalty": { "type": "number" }, "challengeCancelGracePeriodHours": { "type": "number" }, "matchupCooldownHours": { "type": "number" }, "scrimmageAwardsPoints": { "type": "boolean" } }, "required": [ "gameId" ], "description": "Updates league points configuration." }, "RulesRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "description": "Game id to fetch rules and points config for. Required." } }, "required": [ "gameId" ], "description": "Game selector for league rules and points config." }, "ApplyRuleTemplateRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID to apply the template to." }, "templateId": { "type": "string", "minLength": 1, "description": "League rule template ID." } }, "required": [ "gameId", "templateId" ], "description": "Applies a rule template." }, "UpdateGameRulesRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "minLength": 1, "description": "Game ID whose league rules should change." }, "allowedPlaylistIds": { "type": "array", "items": { "type": "string" } }, "allowedMapIds": { "type": "array", "items": { "type": "string" } }, "matchFormat": { "type": "string", "enum": [ "BEST_OF_1", "BEST_OF_3", "BEST_OF_5", "BEST_OF_7", "BEST_OF_9" ] }, "teamSize": { "type": "object", "properties": { "min": { "type": "number" }, "max": { "type": "number" } }, "required": [ "min", "max" ] }, "forceCompetitive": { "type": "boolean" }, "allowedDays": { "type": "array", "items": { "type": "string" } }, "blockedDays": { "type": "array", "items": { "type": "string" } }, "allowedTimeRange": { "type": "object", "properties": { "start": { "type": "string" }, "end": { "type": "string" } }, "required": [ "start", "end" ] }, "timezone": { "type": "string" }, "challengesEnabled": { "type": "boolean" }, "maxChallengesPerTeamPerSeason": { "type": "number" }, "maxPointsMatchesPerPairPer24h": { "type": "number" }, "maxPendingChallengesPerOpponent": { "type": "number" }, "maxPendingChallengesTotal": { "type": "number" }, "challengeCooldownMinutes": { "type": "number" }, "wagersAllowed": { "type": "boolean" }, "minWagerAmount": { "type": "number" }, "maxWagerAmount": { "type": "number" }, "minRosterSize": { "type": "number" }, "maxRosterSize": { "type": "number" }, "rosterLockEnabled": { "type": "boolean" }, "rosterChangeWindowDays": { "type": "array", "items": { "type": "string" } }, "rosterChangeWindowTime": { "type": "object", "properties": { "start": { "type": "string" }, "end": { "type": "string" } }, "required": [ "start", "end" ] }, "maxRosterChangesPerWeek": { "type": "number" } }, "required": [ "gameId" ], "description": "Updates league game rules." }, "LeagueSeasonOptionsRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "description": "Game ID to list season options for." } }, "required": [ "gameId" ], "description": "Season option selector." }, "SeasonsRequestBody": { "type": "object", "properties": { "gameId": { "description": "Filter seasons to a specific game id.", "type": "string" }, "status": { "description": "Filter seasons by lifecycle status.", "type": "string", "enum": [ "UPCOMING", "ACTIVE", "COMPLETED" ] } }, "description": "Game and status filters for league seasons." }, "CreateSeasonRequestBody": { "type": "object", "properties": { "gameId": { "type": "string", "description": "Game ID the season belongs to." }, "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Season name." }, "startDate": { "type": "number", "description": "Season start timestamp in milliseconds." }, "endDate": { "type": "number", "description": "Season end timestamp in milliseconds." } }, "required": [ "gameId", "name", "startDate", "endDate" ], "description": "League season creation payload." }, "SetLeagueEnabledRequestBody": { "type": "object", "properties": { "isEnabled": { "type": "boolean", "description": "Whether the league is enabled/discoverable." } }, "required": [ "isEnabled" ], "description": "League enabled-state update." }, "StandingsRequestBody": { "type": "object", "properties": { "seasonId": { "description": "Filter standings to a specific season id.", "type": "string" }, "gameId": { "description": "Filter standings to a specific game id.", "type": "string" }, "limit": { "default": 50, "description": "Maximum number of teams to return (1-100). Defaults to 50.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "description": "Season and game filters for league standings." }, "DenyLeagueTeamRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional denial reason shown to the team's captain.", "type": "string", "maxLength": 500 } }, "description": "Denies a pending league team application." }, "RemoveLeagueTeamRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional removal reason shown to the team's captain.", "type": "string", "maxLength": 500 } }, "description": "Removes an approved team from a league." }, "UpdateLeagueTicketRequestBody": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "open", "in_progress", "awaiting_response", "resolved", "closed" ] }, "priority": { "type": "string", "enum": [ "low", "medium", "high", "urgent" ] }, "assignedTo": { "description": "User ID to assign, or null to clear assignment.", "anyOf": [ { "type": "string", "minLength": 1 }, { "type": "null" } ] } }, "description": "Updates league ticket status, priority, or assignment." }, "EscalateLeagueTicketRequestBody": { "type": "object", "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 500 } }, "required": [ "reason" ], "description": "Escalates a league support ticket to TeamBattles staff." }, "ReplyLeagueTicketRequestBody": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 2000 }, "isInternal": { "type": "boolean" } }, "required": [ "content" ], "description": "Adds a reply or internal note to a league support ticket." }, "CreateLeagueTicketRequestBody": { "type": "object", "properties": { "subject": { "type": "string", "minLength": 1, "maxLength": 200 }, "description": { "type": "string", "minLength": 1, "maxLength": 2000 }, "priority": { "type": "string", "enum": [ "low", "medium", "high", "urgent" ] } }, "required": [ "subject", "description" ], "description": "Creates a league-scoped support ticket." }, "LeagueTemplatesRequestBody": { "type": "object", "properties": { "gameId": { "description": "Optional game ID filter.", "type": "string" }, "isOfficial": { "description": "Optional official-template filter.", "type": "boolean" } }, "description": "Template filters." }, "AcceptMatchRequestBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Team ID accepting the match." }, "activeRoster": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Active roster user IDs for the acceptance request." }, "benchRoster": { "description": "Optional bench roster users.", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Bench user ID." }, "priority": { "type": "number", "description": "Bench priority." } }, "required": [ "id", "priority" ] } }, "disputedRules": { "description": "Optional proposed rule changes.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "type": "string" } } ] } }, "mapPreferenceMode": { "description": "Optional map preference mode for selected maps.", "type": "string", "enum": [ "PREFERRED", "VETO" ] }, "selectedMaps": { "description": "Optional proposed map IDs.", "type": "array", "items": { "type": "string" } }, "message": { "description": "Optional message for the match creator.", "type": "string" } }, "required": [ "teamId", "activeRoster" ], "description": "Creates a match acceptance request as the API key owner." }, "ApproveAcceptanceRequestBody": { "type": "object", "properties": { "responseMessage": { "description": "Optional message sent to the accepting team.", "type": "string" }, "availableMaps": { "description": "Optional list of available map IDs for the match.", "type": "array", "items": { "type": "string" } } }, "description": "Approves a pending match acceptance as the API key owner." }, "DeclineAcceptanceRequestBody": { "type": "object", "properties": { "responseMessage": { "description": "Optional message sent to the declined team.", "type": "string" } }, "description": "Declines a pending match acceptance as the API key owner." }, "UpdateAttendanceRequestBody": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "ATTENDING", "NOT_ATTENDING", "TENTATIVE" ], "description": "The API key owner's attendance status for this match." } }, "required": [ "status" ], "description": "Updates the API key owner's own attendance status for a match." }, "CancelMatchRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional cancellation reason.", "type": "string" } }, "description": "Cancels the match as the API key owner." }, "AcceptChallengeRequestBody": { "type": "object", "properties": { "activeRoster": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Active roster user IDs for the challenge response." }, "benchRoster": { "description": "Optional bench roster users.", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Bench user ID." }, "priority": { "type": "number", "description": "Bench priority." } }, "required": [ "id", "priority" ] } } }, "required": [ "activeRoster" ], "description": "Accepts a pending challenge as the API key owner." }, "RefuseChallengeRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional reason shown to the challenging team.", "type": "string" } }, "description": "Refuses a pending challenge as the API key owner." }, "SendChatMessageRequestBody": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Message body (1-255 chars)." } }, "required": [ "content" ], "description": "Sends a message to the match chat room as the API key owner." }, "ForfeitMatchRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional forfeit reason.", "type": "string" } }, "description": "Forfeits the match as the API key owner." }, "UpdateLobbyCodeRequestBody": { "type": "object", "properties": { "lobbyCode": { "type": "string", "minLength": 1, "maxLength": 50, "description": "Lobby code to set for the match." } }, "required": [ "lobbyCode" ], "description": "Sets or updates the match lobby code as the API key owner." }, "MarkMatchReadyRequestBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Team ID to mark ready." } }, "required": [ "teamId" ], "description": "Marks one participating team ready as the API key owner." }, "ConfirmScoreBody": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Zero-based map index to confirm. Must be a non-negative integer." } }, "required": [ "mapIndex" ], "description": "Confirmation payload identifying the map score to confirm." }, "SubmitScoreBody": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Zero-based map index. Must be a non-negative integer." }, "mapId": { "type": "string", "description": "Map identifier string (e.g. dust2)." }, "creatorTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Creator team score (integer, 0-1000)." }, "opponentTeamScore": { "type": "integer", "minimum": 0, "maximum": 1000, "description": "Accepted/opponent team score (integer, 0-1000)." }, "screenshotUrls": { "description": "Optional external screenshot URLs (validated as public https server-side, max 10). Prefer screenshotStorageIds for validated blobs.", "maxItems": 10, "type": "array", "items": { "type": "string" } }, "screenshotStorageIds": { "description": "Optional Convex storage ids from POST /api/v1/uploads/image-url (validated for size + content-type, max 10; preferred over screenshotUrls).", "maxItems": 10, "type": "array", "items": { "type": "string" } } }, "required": [ "mapIndex", "mapId", "creatorTeamScore", "opponentTeamScore" ], "description": "Map score submission payload for a single map." }, "CreateMatchRequestBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Creator team ID. The owner must be a captain, co-captain, or org owner of it." }, "gameId": { "type": "string", "minLength": 1, "description": "Game ID for the match." }, "gameModeId": { "type": "string", "minLength": 1, "description": "Game mode ID (client-side definition)." }, "matchType": { "type": "string", "enum": [ "XP_ONLY", "WAGER" ], "description": "Match type." }, "mapSelectionType": { "type": "string", "enum": [ "COMPETITIVE", "FLEX" ], "description": "Map selection type." }, "mapPreferenceMode": { "type": "string", "enum": [ "PREFERRED", "VETO", "MANUAL" ], "description": "Map preference mode." }, "teamSize": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Players per team." }, "bestOf": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Series length (best of N)." }, "platform": { "description": "Platform (defaults to CROSSPLAY).", "type": "string", "enum": [ "PC", "XBOX", "PLAYSTATION", "CONSOLE_ONLY", "CROSSPLAY" ] }, "inputDevice": { "description": "Input device (defaults to ALL).", "type": "string", "enum": [ "ALL", "CONTROLLER", "KB_M" ] }, "region": { "description": "Region (defaults to NONE).", "type": "string", "enum": [ "NONE", "NA_EAST", "NA_WEST", "EU", "ASIA", "OCEANIA", "SOUTH_AMERICA", "MIDDLE_EAST", "AFRICA" ] }, "scheduledAt": { "description": "Scheduled start (epoch ms).", "type": "number" }, "wagerAmount": { "description": "Wager amount (WAGER matches only).", "type": "number" }, "selectedMaps": { "description": "Selected map IDs.", "type": "array", "items": { "type": "string" } }, "selectedObjectives": { "description": "Selected objective IDs.", "type": "array", "items": { "type": "string" } }, "gameSpecificOptions": { "description": "Game-specific options.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" } ] } }, "lockedRules": { "description": "Locked rule flags.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "boolean" } }, "notes": { "description": "Optional match notes.", "type": "string" }, "publishStatus": { "description": "Publish status (defaults to DRAFT).", "type": "string", "enum": [ "DRAFT", "PUBLISHED", "ARCHIVED" ] }, "activeRoster": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Active roster user IDs (must be creator-team members)." }, "benchRoster": { "description": "Optional bench roster.", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Bench user ID." }, "priority": { "type": "number", "description": "Bench priority." } }, "required": [ "id", "priority" ] } }, "isChallenge": { "description": "Create as a direct challenge to another team.", "type": "boolean" }, "challengedTeamId": { "description": "Challenged team ID (required when isChallenge is true).", "type": "string", "minLength": 1 }, "leagueId": { "description": "League ID for a league match.", "type": "string", "minLength": 1 } }, "required": [ "teamId", "gameId", "gameModeId", "matchType", "mapSelectionType", "mapPreferenceMode", "teamSize", "bestOf", "activeRoster" ], "description": "Creates a new match as the API key owner." }, "MatchDiscoverBody": { "type": "object", "properties": { "gameId": { "type": "string" }, "gameSlug": { "type": "string" }, "platform": { "type": "string", "enum": [ "PC", "XBOX", "PLAYSTATION", "CONSOLE_ONLY", "CROSSPLAY" ] }, "region": { "type": "string", "enum": [ "NONE", "NA_EAST", "NA_WEST", "EU", "ASIA", "OCEANIA", "SOUTH_AMERICA", "MIDDLE_EAST", "AFRICA" ] }, "matchType": { "type": "string", "enum": [ "XP_ONLY", "WAGER" ] }, "scheduledAfter": { "type": "string" }, "scheduledBefore": { "type": "string" }, "leagueId": { "type": "string" }, "leagueSeasonId": { "type": "string" }, "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "description": "Filters and cursor pagination for public open-match discovery." }, "CreateOrgBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "description": "Organization name." }, "tag": { "type": "string", "minLength": 1, "description": "Organization tag (short identifier)." }, "description": { "description": "Optional organization description.", "type": "string" } }, "required": [ "name", "tag" ], "description": "Creates a new organization as the API key owner." }, "UpdateOrgBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "tag": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "isPublic": { "type": "boolean" }, "profileVisibility": { "type": "string", "enum": [ "public", "limited", "private" ] } }, "description": "Fields to update on the organization. All optional." }, "MatchesRequestBody": { "type": "object", "properties": { "numItems": { "default": 25, "description": "Page size (1-100). Defaults to 25.", "type": "integer", "minimum": 1, "maximum": 100 }, "cursor": { "description": "Opaque continuation cursor from a prior page's continueCursor.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "includeStatuses": { "description": "Only include matches with these MatchStatus codes; unknown values are ignored.", "type": "array", "items": { "type": "string" } }, "excludeStatuses": { "description": "Exclude matches with these MatchStatus codes; unknown values are ignored.", "type": "array", "items": { "type": "string" } }, "gameId": { "description": "Filter to a single game by id.", "type": "string" }, "scheduledAfter": { "description": "ISO 8601; only matches scheduled at or after this time.", "type": "string" }, "scheduledBefore": { "description": "ISO 8601; only matches scheduled at or before this time.", "type": "string" }, "createdAfter": { "description": "ISO 8601; only matches created at or after this time.", "type": "string" }, "createdBefore": { "description": "ISO 8601; only matches created at or before this time.", "type": "string" }, "opponentId": { "description": "Filter to matches against this opponent team (team id or slug).", "type": "string" } }, "description": "Filters and cursor pagination for listing matches." }, "AddOrgMemberBody": { "type": "object", "properties": { "targetUserId": { "type": "string", "minLength": 1, "description": "Convex user ID of the member to add." }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER" ], "description": "The role to assign to the new member. Ownership is set on creation." } }, "required": [ "targetUserId", "role" ], "description": "Add a member to the organization." }, "SetOrgMemberRoleBody": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "ADMIN", "MANAGER", "MEMBER" ], "description": "The new role for the member. The owner role is changed via ownership transfer." } }, "required": [ "role" ], "description": "Set an organization member's role." }, "TransferOrgOwnershipBody": { "type": "object", "properties": { "newOwnerId": { "type": "string", "minLength": 1, "description": "Convex user ID of the active organization member to promote to owner." } }, "required": [ "newOwnerId" ], "description": "Transfer organization ownership to another member." }, "ApiBatchStreamStatusBody": { "type": "object", "properties": { "userIds": { "minItems": 1, "maxItems": 50, "type": "array", "items": { "type": "string" }, "description": "User IDs to look up (1-50)." } }, "required": [ "userIds" ], "description": "Batch live-status request body." }, "CreateTeamBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "description": "Team name." }, "tag": { "type": "string", "minLength": 1, "description": "Team tag (short identifier)." }, "gameId": { "type": "string", "minLength": 1, "description": "Game ID the team competes in." }, "playlistId": { "type": "string", "minLength": 1, "description": "Game playlist ID." }, "organizationId": { "type": "string", "minLength": 1, "description": "Owning organization ID. The owner must manage it." }, "description": { "description": "Optional team description.", "type": "string" }, "platform": { "description": "Optional platform.", "type": "string" }, "region": { "description": "Optional region.", "type": "string" } }, "required": [ "name", "tag", "gameId", "playlistId", "organizationId" ], "description": "Creates a new team as the API key owner." }, "UpdateTeamBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "tag": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "platform": { "type": "string" }, "region": { "type": "string", "enum": [ "NONE", "NA_EAST", "NA_WEST", "EU", "ASIA", "OCEANIA", "SOUTH_AMERICA", "MIDDLE_EAST", "AFRICA" ] }, "profileVisibility": { "type": "string", "enum": [ "public", "limited", "private" ] } }, "description": "Fields to update on the team. All optional." }, "TransferTeamCaptaincyBody": { "type": "object", "properties": { "newCaptainId": { "type": "string", "minLength": 1, "description": "Convex user ID of the active team member to promote to captain." } }, "required": [ "newCaptainId" ], "description": "Transfer team captaincy to another member." }, "SetTeamMemberRoleBody": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "CO_CAPTAIN", "MEMBER" ], "description": "The new role for the member. Captaincy is changed via captaincy transfer." } }, "required": [ "role" ], "description": "Set a team member's role." }, "CreateTicketRequestBody": { "type": "object", "properties": { "subject": { "type": "string", "minLength": 1, "maxLength": 150, "description": "Ticket subject (max 150 chars)." }, "description": { "type": "string", "minLength": 1, "maxLength": 2000, "description": "Initial message / description (max 2000 chars)." }, "category": { "type": "string", "enum": [ "account", "technical_bug", "feature_request", "billing", "other" ], "description": "Support category. Entity-bound and staff-only categories are rejected." }, "images": { "description": "Optional storage IDs (from /uploads/image-url) to attach (max 10).", "maxItems": 10, "type": "array", "items": { "type": "string" } } }, "required": [ "subject", "description", "category" ], "description": "Creates a self-filed support ticket owned by the API key owner." }, "AddTicketMessageRequestBody": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 2000, "description": "Reply message body (max 2000 chars)." }, "images": { "description": "Optional storage IDs (from /uploads/image-url) to attach (max 10).", "maxItems": 10, "type": "array", "items": { "type": "string" } } }, "required": [ "content" ], "description": "Adds a reply message to one of the API key owner's tickets." }, "TournamentCreateRequestBody": { "type": "object", "properties": { "hostType": { "type": "string", "enum": [ "user", "org", "league" ], "description": "Who hosts the tournament. This choice, together with `hostId`, decides which plan is billed for every later organizer request on the tournament - see the endpoint description." }, "hostId": { "type": "string", "description": "Your own user id when hostType is `user`; the organization id when `org`; the league id when `league`. You must genuinely hold that authority - see the endpoint description." }, "name": { "type": "string", "minLength": 3, "maxLength": 80, "description": "Tournament name, 3-80 characters after trimming." }, "description": { "type": "string", "maxLength": 5000 }, "rules": { "type": "string", "maxLength": 20000 }, "gameId": { "type": "string", "description": "Convex game id." }, "playlistId": { "description": "Convex game playlist id.", "type": "string" }, "teamSize": { "type": "integer", "minimum": 1, "maximum": 9007199254740991, "description": "Players per side." }, "defaultMatchConfig": { "$ref": "#/components/schemas/TournamentDefaultMatchConfig" }, "format": { "$ref": "#/components/schemas/TournamentFormat" }, "formatConfig": { "$ref": "#/components/schemas/TournamentFormatConfig" }, "minParticipants": { "type": "integer", "minimum": 2, "maximum": 9007199254740991 }, "maxParticipants": { "type": "integer", "minimum": 2, "maximum": 9007199254740991, "description": "Entrant cap. Also bounded by the format ceiling (SINGLE_ELIMINATION and DOUBLE_ELIMINATION 128, SWISS 64, ROUND_ROBIN 32) and by the host plan's participant limit, both checked server-side." }, "registrationMode": { "type": "string", "enum": [ "OPEN", "APPLICATION", "INVITE_ONLY" ] }, "registrationStartsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "registrationEndsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "checkInRequired": { "type": "boolean" }, "checkInOpensMinutesBefore": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "freeAgentsEnabled": { "type": "boolean", "description": "Whether unaffiliated players may join a free-agent pool. NOT editable afterwards through the update endpoint." }, "seedingMethod": { "description": "Defaults to the platform default when omitted. NOT editable afterwards.", "type": "string", "enum": [ "MANUAL", "RANDOM", "REGISTRATION" ] }, "startsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "endsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "prizePool": { "type": "number", "minimum": 0 }, "prizeCurrency": { "type": "string", "maxLength": 10 }, "prizeBreakdown": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentPrizeBreakdownEntry" } }, "prizeDescription": { "type": "string", "maxLength": 2000 }, "bannerStorageId": { "description": "Convex storage id.", "type": "string" }, "logoStorageId": { "description": "Convex storage id.", "type": "string" }, "socialLinks": { "$ref": "#/components/schemas/TournamentSocialLinks" }, "sponsorTags": { "description": "Bounded by the host plan's sponsor-tag limit.", "type": "array", "items": { "$ref": "#/components/schemas/TournamentSponsorTag" } }, "visibility": { "type": "string", "enum": [ "PUBLIC", "UNLISTED" ] }, "leaguePointsEnabled": { "description": "LEAGUE HOSTS ONLY. Sending it with a user or org host is a 400.", "type": "boolean" }, "leaguePointsByPlacement": { "description": "LEAGUE HOSTS ONLY. Omit to use the platform default curve; an empty array is rejected.", "type": "array", "items": { "$ref": "#/components/schemas/TournamentPlacementPointsEntry" } } }, "required": [ "hostType", "hostId", "name", "gameId", "teamSize", "defaultMatchConfig", "format", "formatConfig", "minParticipants", "maxParticipants", "registrationMode", "checkInRequired", "freeAgentsEnabled", "visibility" ], "description": "A new tournament. Fields this schema does not list are IGNORED rather than rejected, so a misspelled key silently does nothing - this matters most inside `defaultMatchConfig`, where a dropped key would produce a tournament whose matches cannot be generated." }, "TournamentDefaultMatchConfig": { "type": "object", "properties": { "gameModeId": { "type": "string", "minLength": 1, "description": "Game mode every generated match is played in. Validated against the game's allowed modes when a match is generated, NOT here - a mode id that does not belong to `gameId` is accepted at create time and surfaces at start time as a match_generation_failed activity entry." }, "mapSelectionType": { "type": "string", "enum": [ "COMPETITIVE", "FLEX" ] }, "mapPreferenceMode": { "type": "string", "enum": [ "PREFERRED", "VETO", "MANUAL" ], "description": "Overridden to MANUAL for the grand final when formatConfig.grandFinalAdvantage.type is MAP_SELECTION." }, "platform": { "type": "string", "enum": [ "PC", "XBOX", "PLAYSTATION", "CONSOLE_ONLY", "CROSSPLAY" ] }, "inputDevice": { "type": "string", "enum": [ "ALL", "CONTROLLER", "KB_M" ] }, "region": { "type": "string", "enum": [ "NONE", "NA_EAST", "NA_WEST", "EU", "ASIA", "OCEANIA", "SOUTH_AMERICA", "MIDDLE_EAST", "AFRICA" ] }, "selectedMaps": { "type": "array", "items": { "type": "string" }, "description": "Map pool for every generated match. A per-round `mapPoolOverride` REPLACES this array for that round rather than merging into it." }, "selectedObjectives": { "type": "array", "items": { "type": "string" } }, "gameSpecificOptions": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" } ] } }, "lockedRules": { "description": "Rule keys neither team may renegotiate on a generated match.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "boolean" } } }, "required": [ "gameModeId", "mapSelectionType", "mapPreferenceMode", "platform", "inputDevice", "region", "selectedMaps" ], "description": "Match settings stamped onto every match this tournament generates. Required, and sent whole - there is no per-field default." }, "TournamentFormat": { "type": "string", "enum": [ "SINGLE_ELIMINATION", "DOUBLE_ELIMINATION", "ROUND_ROBIN", "SWISS" ], "description": "Bracket format of a tournament." }, "TournamentFormatConfig": { "type": "object", "properties": { "bestOfLadder": { "type": "object", "properties": { "default": { "type": "integer", "minimum": 1, "maximum": 9007199254740991, "description": "Default best-of for every round." }, "overrides": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "description": "Per-round best-of overrides, keyed by round key (e.g. `GF`, `R1`)." } }, "required": [ "default", "overrides" ], "description": "Best-of ladder. Both fields are required when formatConfig is sent." }, "grandFinalAdvantage": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "NONE", "WIN_HEADSTART", "MAP_SELECTION", "BRACKET_RESET" ] }, "winHeadstart": { "description": "Maps the upper-bracket finalist starts ahead by. WIN_HEADSTART only.", "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "type" ] }, "swissRoundCount": { "description": "Swiss only. Number of rounds to play.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "roundRobinPasses": { "description": "Round-robin only. 1 = single pass, 2 = double pass.", "anyOf": [ { "type": "number", "const": 1 }, { "type": "number", "const": 2 } ] } }, "required": [ "bestOfLadder", "grandFinalAdvantage" ], "description": "Format-specific configuration. Sent whole - it replaces the stored object rather than merging into it." }, "TournamentPrizeBreakdownEntry": { "type": "object", "properties": { "placement": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "amount": { "type": "number", "minimum": 0 }, "description": { "type": "string", "maxLength": 200 } }, "required": [ "placement" ], "description": "One prize-pool placement row." }, "TournamentSocialLinks": { "type": "object", "properties": { "website": { "type": "string" }, "x": { "type": "string" }, "discord": { "type": "string" }, "youtube": { "type": "string" }, "twitch": { "type": "string" }, "instagram": { "type": "string" }, "tiktok": { "type": "string" } }, "description": "Organizer social links." }, "TournamentSponsorTag": { "type": "object", "properties": { "prefix": { "type": "string", "enum": [ "POWERED_BY", "SPONSORED_BY", "PRESENTED_BY", "CUSTOM" ] }, "customPrefix": { "description": "Used only when prefix is CUSTOM.", "type": "string", "maxLength": 40 }, "name": { "type": "string", "minLength": 1, "maxLength": 80 }, "url": { "type": "string" }, "logoStorageId": { "description": "Convex storage id for the sponsor logo.", "type": "string" } }, "required": [ "prefix", "name" ], "description": "One sponsor credit line." }, "TournamentPlacementPointsEntry": { "type": "object", "properties": { "placement": { "type": "integer", "minimum": 1, "maximum": 9007199254740991, "description": "Final placement, 1 = champion." }, "points": { "type": "number", "minimum": 0, "maximum": 1000, "description": "League points awarded, 0-1000." } }, "required": [ "placement", "points" ], "description": "One placement -> points row." }, "TournamentDenyApplicationBody": { "type": "object", "properties": { "reason": { "description": "Optional reason shown to the applying captain.", "type": "string", "maxLength": 500 } }, "description": "Application denial payload." }, "TournamentCancelRequestBody": { "type": "object", "properties": { "reason": { "description": "Optional human-readable cancellation reason. It is echoed to participants in the cancellation notification and in the `tournament.cancelled` webhook payload, so treat it as PUBLIC.", "type": "string", "maxLength": 500 } }, "description": "Tournament cancellation payload." }, "TournamentFreeAgencyJoinBody": { "type": "object", "properties": { "note": { "description": "Optional public note shown to captains browsing the pool - roles played, availability, and so on.", "type": "string", "maxLength": 500 } }, "description": "Free-agent pool listing payload for the API key owner." }, "TournamentOfferRespondBody": { "type": "object", "properties": { "accept": { "type": "boolean", "description": "true to accept the offer and join the offering team's roster, false to decline it. A competitive ban blocks accepting but never declining." } }, "required": [ "accept" ], "description": "Free agent's response to a pickup offer." }, "TournamentSendOfferBody": { "type": "object", "properties": { "participantId": { "type": "string", "minLength": 1, "description": "Participant ID of YOUR team making the offer. You must be its captain, co-captain, or the owner of the organization that owns it, and it must be APPROVED in this tournament. Discover it via GET /tournaments/{identifier}/me." }, "message": { "description": "Optional message delivered to the free agent alongside the offer.", "type": "string", "maxLength": 1000 } }, "required": [ "participantId" ], "description": "Free-agent pickup offer payload." }, "TournamentInviteTeamBody": { "type": "object", "properties": { "teamId": { "type": "string", "minLength": 1, "description": "Team ID to invite." } }, "required": [ "teamId" ], "description": "Tournament team invitation payload." }, "TournamentInviteRespondBody": { "type": "object", "properties": { "accept": { "type": "boolean", "description": "true to accept the invite and enter the tournament, false to decline it. A competitive ban blocks accepting but never declining." }, "roster": { "description": "User IDs to register as the team's tournament roster. REQUIRED when accept is true and ignored when it is false. Every entry must be an ACTIVE member of the invited team, and the array must hold at least the tournament's teamSize members - a shorter roster answers 400 error_roster_too_small.", "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "accept" ], "description": "Captain response to a tournament invite." }, "TournamentLeaguePointsRequestBody": { "type": "object", "properties": { "leaguePointsEnabled": { "type": "boolean", "description": "Whether finishing this tournament awards league points to the league season." }, "leaguePointsByPlacement": { "description": "The placement curve. OMIT the field entirely to fall back to the platform default curve - an empty array is NOT the way to award nothing and is rejected as EMPTY (use `leaguePointsEnabled: false` for that). The table is validated even when `leaguePointsEnabled` is false.", "type": "array", "items": { "$ref": "#/components/schemas/TournamentPlacementPointsEntry" } } }, "required": [ "leaguePointsEnabled" ], "description": "League placement-points configuration." }, "TournamentOverrideNodeResultBody": { "type": "object", "properties": { "score1": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Score for the node's first entrant." }, "score2": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Score for the node's second entrant." } }, "required": [ "score1", "score2" ], "description": "Bracket node result override payload." }, "TournamentRevertNodeResultBody": { "type": "object", "properties": { "regenerateMatch": { "description": "Whether to generate a fresh match for the reverted node. Defaults to true when omitted.", "type": "boolean" } }, "description": "Bracket node result revert payload." }, "TournamentDisqualifyParticipantBody": { "type": "object", "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Required reason for the disqualification." } }, "required": [ "reason" ], "description": "Participant disqualification payload." }, "TournamentRemoveParticipantBody": { "type": "object", "properties": { "reason": { "description": "Optional reason recorded on the activity log entry.", "type": "string", "maxLength": 500 } }, "description": "Participant removal payload." }, "TournamentOrganizerRosterAddBody": { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1, "description": "User ID of the member to add to the participant's roster." } }, "required": [ "userId" ], "description": "Organizer roster addition payload." }, "TournamentRegenerateMatchesRequestBody": { "type": "object", "properties": { "confirm": { "type": "boolean", "const": true, "description": "Must be exactly `true`. Required so this repair lever cannot be fired by an empty or accidental POST." } }, "required": [ "confirm" ], "description": "Confirmation payload for the match-regeneration repair lever." }, "TournamentRoundScheduleRequestBody": { "type": "object", "properties": { "startsAt": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "Unix ms the round is scheduled to start, or null to clear the round's scheduled time. REQUIRED - there is no 'leave unchanged' value, because omitting it in the underlying mutation clears the field, and a silent clear is not something an integrator should be able to trigger by forgetting a key." } }, "required": [ "startsAt" ], "description": "Round schedule payload." }, "TournamentAddStaffBody": { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1, "description": "User ID of the staff member to add." }, "role": { "$ref": "#/components/schemas/TournamentStaffRole" } }, "required": [ "userId", "role" ], "description": "Tournament staff addition payload." }, "TournamentStaffRole": { "type": "string", "enum": [ "ADMIN", "MODERATOR" ], "description": "Tournament staff role." }, "TournamentStartRequestBody": { "type": "object", "properties": { "seedMethod": { "type": "string", "enum": [ "manual", "random", "registration" ], "description": "How to order participants into seeds. `manual` requires `manualOrder`. `random` is deterministic for a given tournament, not re-rollable. `registration` seeds by registration order." }, "manualOrder": { "description": "Participant ids in seed order, seed 1 first. REQUIRED when `seedMethod` is `manual`. Every id must belong to this tournament (a foreign id answers 404) and duplicates are rejected. The list must still match the participant set AFTER the check-in drop below, so build it from the participants that are actually checked in.", "minItems": 1, "type": "array", "items": { "type": "string" } } }, "required": [ "seedMethod" ], "description": "Tournament start payload." }, "TournamentTeamEntryBody": { "type": "object", "properties": { "roster": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "User IDs to register as the team's tournament roster. Every entry must be an ACTIVE member of the team named in the path, and the array must hold at least the tournament's teamSize members - a shorter roster answers 400 error_roster_too_small. Users already rostered in this tournament are skipped rather than rejected." } }, "required": [ "roster" ], "description": "Tournament entry payload for a team the caller leads." }, "TournamentTeamRosterAddBody": { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1, "description": "User ID of the member to add to YOUR team's tournament roster. The participant is resolved from the team in the path and is never supplied in the body." } }, "required": [ "userId" ], "description": "Competitor roster addition payload." }, "TournamentUpdateRequestBody": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "description": { "type": "string", "maxLength": 5000 }, "rules": { "type": "string", "maxLength": 20000 }, "gameId": { "description": "Convex game id.", "type": "string" }, "playlistId": { "description": "Convex game playlist id.", "type": "string" }, "teamSize": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "format": { "type": "string", "enum": [ "SINGLE_ELIMINATION", "DOUBLE_ELIMINATION", "ROUND_ROBIN", "SWISS" ] }, "formatConfig": { "$ref": "#/components/schemas/TournamentFormatConfig" }, "minParticipants": { "type": "integer", "minimum": 2, "maximum": 9007199254740991 }, "maxParticipants": { "description": "Re-checked against the format entrant ceiling AND the host plan's participant limit whenever it or `format` changes.", "type": "integer", "minimum": 2, "maximum": 9007199254740991 }, "registrationMode": { "type": "string", "enum": [ "OPEN", "APPLICATION", "INVITE_ONLY" ] }, "registrationStartsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "registrationEndsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "checkInRequired": { "type": "boolean" }, "checkInOpensMinutesBefore": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "startsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "endsAt": { "description": "Unix ms.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "prizePool": { "type": "number", "minimum": 0 }, "prizeCurrency": { "type": "string", "maxLength": 10 }, "prizeBreakdown": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentPrizeBreakdownEntry" } }, "prizeDescription": { "type": "string", "maxLength": 2000 }, "bannerStorageId": { "description": "Convex storage id.", "type": "string" }, "logoStorageId": { "description": "Convex storage id.", "type": "string" }, "socialLinks": { "$ref": "#/components/schemas/TournamentSocialLinks" }, "sponsorTags": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentSponsorTag" } }, "visibility": { "type": "string", "enum": [ "PUBLIC", "UNLISTED" ] } }, "description": "Partial tournament edit. Send only the fields you are changing; at least one recognised field is required. Fields this schema does not list are IGNORED rather than rejected, so a misspelled key silently does nothing - check the response `applied` value and `changedFields`. `freeAgentsEnabled`, `seedingMethod` and the league-points settings are NOT editable here (league points has its own endpoint)." }, "TournamentDiscoverBody": { "type": "object", "properties": { "search": { "description": "Case-insensitive name substring. Ignored below 2 characters.", "type": "string" }, "gameId": { "description": "Filter to a single game by Convex ID.", "type": "string" }, "format": { "description": "Filter by bracket format.", "$ref": "#/components/schemas/TournamentFormat" }, "status": { "description": "Filter by lifecycle status.", "$ref": "#/components/schemas/TournamentStatus" }, "page": { "default": 1, "description": "1-based page number.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "limit": { "default": 12, "description": "Page size, 1-50.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "description": "Filters for public tournament discovery." }, "TournamentStatus": { "type": "string", "enum": [ "DRAFT", "REGISTRATION_OPEN", "REGISTRATION_CLOSED", "IN_PROGRESS", "COMPLETED", "CANCELLED" ], "description": "Lifecycle status of a tournament." }, "GameRankUpsertBody": { "type": "object", "properties": { "gameId": { "type": "string", "enum": [ "call_of_duty_black_ops_7", "valorant", "league_of_legends", "counter_strike_2" ], "description": "Game definition ID to set the rank for (a playable game)." }, "mode": { "type": "string", "minLength": 1, "maxLength": 64, "description": "Game mode / playlist the rank applies to (a valid playlist ID)." }, "sr": { "type": "integer", "minimum": 0, "maximum": 100000, "description": "Skill rating (integer, 0-100000)." }, "isTop250": { "description": "Whether the player is in the Top 250 ladder.", "type": "boolean" }, "top250Rank": { "description": "Top 250 ladder position (1-250); only meaningful when isTop250.", "type": "integer", "minimum": 1, "maximum": 250 }, "winstreak": { "description": "Current win streak count (0-99).", "type": "integer", "minimum": 0, "maximum": 99 } }, "required": [ "gameId", "mode", "sr" ], "description": "Upsert the API key owner's rank for one (gameId, mode) slot." }, "CreateWebhookBody": { "type": "object", "properties": { "url": { "type": "string", "description": "HTTPS endpoint URL. Private/loopback/metadata hosts are rejected." }, "events": { "minItems": 1, "type": "array", "items": { "type": "string" }, "description": "Subscribed event tokens: exact catalog names (e.g. match.completed) or family wildcards (e.g. match.*). At least one required." }, "label": { "description": "Optional human label for the endpoint.", "type": "string" }, "leagueId": { "description": "League id - creates a league-scoped endpoint; requires current league ADMIN membership; gated on the league owner's plan.", "type": "string" } }, "required": [ "url", "events" ], "description": "Create a webhook endpoint in the caller's scope." }, "UpdateWebhookBody": { "type": "object", "properties": { "url": { "description": "New HTTPS endpoint URL.", "type": "string" }, "events": { "description": "Replacement event token list (at least one when present).", "minItems": 1, "type": "array", "items": { "type": "string" } }, "label": { "description": "New human label.", "type": "string" }, "isActive": { "description": "Enable/disable the endpoint. Re-enabling resets the failure count.", "type": "boolean" } }, "description": "Partial update of a webhook endpoint." }, "AchievementUnlockedPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "achievementId": { "type": "string", "description": "TeamBattles document id." }, "unlockedAt": { "type": "number", "description": "Unix epoch milliseconds." } }, "required": [ "userId", "achievementId" ], "description": "A user unlocked an achievement." }, "ChatMessageReportedPayload": { "type": "object", "properties": { "reportId": { "type": "string", "description": "TeamBattles document id." }, "messageId": { "type": "string", "description": "TeamBattles document id." }, "matchId": { "type": "string", "description": "TeamBattles document id." }, "reporterUserId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "reportId" ], "description": "A chat message was reported." }, "CustomMapScanCompletedPayload": { "type": "object", "properties": { "customMapId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "status": { "type": "string" } }, "required": [ "customMapId" ], "description": "A custom map scan completed." }, "LeagueAnnouncementPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} }, "title": { "type": "string" }, "body": { "type": "string" }, "announcedByUserId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "leagueId" ], "description": "A league staff announcement was published." }, "LeagueBanRevokedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league ban was revoked." }, "LeagueCooldownClearedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league cooldown was cleared." }, "LeagueCooldownIssuedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league cooldown was issued." }, "LeagueCreatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was created." }, "LeagueDisplayRulesUpdatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League display rules changed." }, "LeagueFeaturedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was featured." }, "LeagueGameAddedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A game was added to a league." }, "LeagueGameRemovedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A game was removed from a league." }, "LeagueGameToggledPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league game was toggled." }, "LeagueOwnershipTransferredPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League ownership changed." }, "LeaguePenaltyIssuedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league penalty was issued." }, "LeaguePointsUpdatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League points configuration changed." }, "LeagueRulesUpdatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League rules changed." }, "LeagueSeasonActivatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league season was activated." }, "LeagueSeasonCompletedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league season was completed." }, "LeagueSeasonCreatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league season was created." }, "LeagueSeasonRemovedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league season was removed." }, "LeagueSettingsUpdatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League settings changed." }, "LeagueShutdownPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was shut down." }, "LeagueShutdownRequestedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League shutdown was requested." }, "LeagueStaffInvitedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League staff was invited." }, "LeagueStaffRemovedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "League staff was removed." }, "LeagueStaffRoleChangedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league staff role changed." }, "LeagueStandingsUpdatedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} }, "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "leagueId" ], "description": "League standings changed." }, "LeagueSuspendedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was suspended." }, "LeagueTeamApprovedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league team application was approved." }, "LeagueTeamBannedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league team was banned." }, "LeagueTeamDeniedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league team application was denied." }, "LeagueTeamRemovedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league team was removed." }, "LeagueUnfeaturedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was unfeatured." }, "LeagueUnsuspendedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was unsuspended." }, "LeagueVerifiedPayload": { "type": "object", "properties": { "leagueId": { "type": "string", "description": "TeamBattles document id." }, "actorId": { "type": "string", "description": "TeamBattles document id." }, "targetType": { "type": "string" }, "targetId": { "type": "string" }, "metadata": { "type": "object", "properties": {}, "additionalProperties": {} } }, "required": [ "leagueId" ], "description": "A league was verified." }, "MatchAcceptedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId" ], "description": "A match was accepted." }, "MatchCancelledPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "reason": { "type": "string" } }, "required": [ "matchId" ], "description": "A match was cancelled." }, "MatchCompletedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "winnerTeamId": { "type": "string", "description": "TeamBattles document id." }, "loserTeamId": { "type": "string", "description": "TeamBattles document id." }, "isDraw": { "type": "boolean" } }, "required": [ "matchId" ], "description": "A match completed with a result." }, "MatchCreatedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId" ], "description": "A match was created." }, "MatchForfeitedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "forfeitedByTeamId": { "type": "string", "description": "TeamBattles document id." }, "reason": { "type": "string" } }, "required": [ "matchId" ], "description": "A match was forfeited." }, "MatchPublishedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId" ], "description": "A match was published." }, "MatchReadyPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId" ], "description": "A match became ready." }, "MatchStartedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId" ], "description": "A match started." }, "OrganizationCreatedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId" ], "description": "An organization was created." }, "OrganizationDisabledPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId" ], "description": "An organization was disabled." }, "OrganizationEnabledPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId" ], "description": "An organization was enabled." }, "OrganizationMemberAddedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "role": { "type": "string" } }, "required": [ "organizationId", "userId" ], "description": "An organization member was added." }, "OrganizationMemberRemovedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId", "userId" ], "description": "An organization member was removed." }, "OrganizationMemberRoleChangedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "oldRole": { "type": "string" }, "newRole": { "type": "string" } }, "required": [ "organizationId", "userId" ], "description": "An organization member role changed." }, "OrganizationOwnershipTransferredPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "oldOwnerId": { "type": "string", "description": "TeamBattles document id." }, "newOwnerId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId", "newOwnerId" ], "description": "Organization ownership changed." }, "OrganizationRemovedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId" ], "description": "An organization was removed." }, "OrganizationUnbannedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "organizationId", "userId" ], "description": "An organization user ban was revoked." }, "OrganizationUpdatedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "fields": { "type": "array", "items": { "type": "string" } } }, "required": [ "organizationId" ], "description": "An organization was updated." }, "OrganizationUserBannedPayload": { "type": "object", "properties": { "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "reason": { "type": "string" } }, "required": [ "organizationId", "userId" ], "description": "A user was banned from an organization." }, "PaymentFailedPayload": { "type": "object", "properties": { "paymentId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "amount": { "type": "number" }, "currency": { "type": "string" } }, "required": [ "paymentId" ], "description": "A payment failed." }, "PaymentRefundedPayload": { "type": "object", "properties": { "paymentId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "amount": { "type": "number" }, "currency": { "type": "string" } }, "required": [ "paymentId" ], "description": "A payment was refunded." }, "PaymentSucceededPayload": { "type": "object", "properties": { "paymentId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "amount": { "type": "number" }, "currency": { "type": "string" } }, "required": [ "paymentId" ], "description": "A payment succeeded." }, "PlayerCheckedInPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "teamId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "checkedInAt": { "type": "number", "description": "Unix epoch milliseconds." } }, "required": [ "matchId", "userId" ], "description": "A player checked in." }, "PlayerStatsUpdatedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "teamId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "stats": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" } ] } } }, "required": [ "matchId", "userId" ], "description": "Player stats changed." }, "RankUpdatedPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "oldRank": { "type": "string" }, "newRank": { "type": "string" }, "source": { "type": "string" } }, "required": [ "userId" ], "description": "A user rank changed." }, "ReferralMilestonePayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "referralId": { "type": "string", "description": "TeamBattles document id." }, "milestone": { "type": "string" } }, "required": [ "userId" ], "description": "A referral milestone was reached." }, "RosterUpdatedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "teamId": { "type": "string", "description": "TeamBattles document id." }, "playerIds": { "type": "array", "items": { "type": "string", "description": "TeamBattles document id." } } }, "required": [ "matchId" ], "description": "A match roster changed." }, "ScoreConfirmedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "mapIndex": { "type": "number" }, "mapName": { "type": "string" }, "creatorTeamScore": { "type": "number" }, "acceptedTeamScore": { "type": "number" }, "confirmedByUserId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "matchId", "mapIndex" ], "description": "A score was confirmed." }, "ScoreDisputeResolvedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "mapIndex": { "type": "number" }, "resolvedByUserId": { "type": "string", "description": "TeamBattles document id." }, "resolution": { "type": "string" } }, "required": [ "matchId" ], "description": "A score dispute was resolved." }, "ScoreDisputedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "mapIndex": { "type": "number" }, "disputedByUserId": { "type": "string", "description": "TeamBattles document id." }, "reason": { "type": "string" } }, "required": [ "matchId" ], "description": "A score was disputed." }, "ScoreSubmittedPayload": { "type": "object", "properties": { "matchId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "leagueSeasonId": { "type": "string", "description": "TeamBattles document id." }, "creatorTeamId": { "type": "string", "description": "TeamBattles document id." }, "acceptedTeamId": { "type": "string", "description": "TeamBattles document id." }, "mapIndex": { "type": "number" }, "mapName": { "type": "string" }, "creatorTeamScore": { "type": "number" }, "acceptedTeamScore": { "type": "number" }, "submittedByUserId": { "type": "string", "description": "TeamBattles document id." }, "autoConfirmed": { "type": "boolean" } }, "required": [ "matchId", "mapIndex" ], "description": "A score was submitted." }, "StreamOfflinePayload": { "type": "object", "properties": { "channelId": { "type": "string" }, "userId": { "type": "string", "description": "TeamBattles document id." }, "platform": { "type": "string" }, "endedAt": { "type": "number", "description": "Unix epoch milliseconds." } }, "required": [ "channelId" ], "description": "A stream went offline." }, "StreamOnlinePayload": { "type": "object", "properties": { "channelId": { "type": "string" }, "userId": { "type": "string", "description": "TeamBattles document id." }, "platform": { "type": "string" }, "startedAt": { "type": "number", "description": "Unix epoch milliseconds." } }, "required": [ "channelId" ], "description": "A stream went online." }, "SubscriptionCancelledPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "productFamily": { "type": "string" }, "planId": { "type": "string" } }, "required": [ "userId" ], "description": "A subscription was cancelled." }, "SubscriptionCreatedPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "productFamily": { "type": "string" }, "planId": { "type": "string" } }, "required": [ "userId" ], "description": "A subscription was created." }, "SubscriptionUpdatedPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "productFamily": { "type": "string" }, "planId": { "type": "string" } }, "required": [ "userId" ], "description": "A subscription changed." }, "TeamBannedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." }, "reason": { "type": "string" } }, "required": [ "teamId" ], "description": "A team was banned." }, "TeamCreatedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "teamId" ], "description": "A team was created." }, "TeamDisbandedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "teamId" ], "description": "A team was disbanded." }, "TeamJoinedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." }, "matchId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "teamId" ], "description": "A team joined a match or league." }, "TeamLeftPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." }, "matchId": { "type": "string", "description": "TeamBattles document id." }, "leagueId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "teamId" ], "description": "A team left a match or league." }, "TeamMemberRoleChangedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "oldRole": { "type": "string" }, "newRole": { "type": "string" } }, "required": [ "teamId", "userId" ], "description": "A team member role changed." }, "TeamUpdatedPayload": { "type": "object", "properties": { "teamId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "organizationId": { "type": "string", "description": "TeamBattles document id." }, "fields": { "type": "array", "items": { "type": "string" } } }, "required": [ "teamId" ], "description": "A team was updated." }, "TicketClosedPayload": { "type": "object", "properties": { "ticketId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "category": { "type": "string" } }, "required": [ "ticketId" ], "description": "A support ticket was closed." }, "TicketCreatedPayload": { "type": "object", "properties": { "ticketId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "category": { "type": "string" } }, "required": [ "ticketId" ], "description": "A support ticket was created." }, "TicketReopenedPayload": { "type": "object", "properties": { "ticketId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "category": { "type": "string" } }, "required": [ "ticketId" ], "description": "A support ticket was reopened." }, "TicketUpdatedPayload": { "type": "object", "properties": { "ticketId": { "type": "string", "description": "TeamBattles document id." }, "userId": { "type": "string", "description": "TeamBattles document id." }, "fields": { "type": "array", "items": { "type": "string" } } }, "required": [ "ticketId" ], "description": "A support ticket changed." }, "TournamentApprovedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" } }, "required": [ "tournamentId" ], "description": "A tournament was approved." }, "TournamentCancelledPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "reason": { "type": "string" } }, "required": [ "tournamentId" ], "description": "A tournament was cancelled." }, "TournamentCompletedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "championParticipantId": { "type": "string", "description": "TeamBattles document id." }, "championName": { "type": "string" }, "placements": { "type": "array", "items": { "type": "object", "properties": { "participantId": { "type": "string", "description": "TeamBattles document id." }, "placement": { "type": "number" } }, "required": [ "participantId", "placement" ] } } }, "required": [ "tournamentId" ], "description": "A tournament completed." }, "TournamentFeaturedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "featuredUntil": { "type": "number", "description": "Unix epoch milliseconds." }, "actorId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "tournamentId" ], "description": "A tournament was featured." }, "TournamentParticipantApprovedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "teamId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "tournamentId" ], "description": "A tournament participant was approved." }, "TournamentRegistrationOpenedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" } }, "required": [ "tournamentId" ], "description": "Tournament registration opened." }, "TournamentRoundCompletedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "roundKey": { "type": "string" } }, "required": [ "tournamentId" ], "description": "A tournament round completed." }, "TournamentStartedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" } }, "required": [ "tournamentId" ], "description": "A tournament started." }, "TournamentUnfeaturedPayload": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "TeamBattles document id." }, "hostType": { "type": "string" }, "hostId": { "type": "string", "description": "TeamBattles document id." }, "gameId": { "type": "string", "description": "TeamBattles document id." }, "format": { "type": "string" }, "status": { "type": "string" }, "actorId": { "type": "string", "description": "TeamBattles document id." } }, "required": [ "tournamentId" ], "description": "A tournament was unfeatured." }, "TrophyAwardedPayload": { "type": "object", "properties": { "userId": { "type": "string", "description": "TeamBattles document id." }, "trophyId": { "type": "string", "description": "TeamBattles document id." }, "awardedAt": { "type": "number", "description": "Unix epoch milliseconds." } }, "required": [ "userId", "trophyId" ], "description": "A trophy was awarded." }, "ReportChatMessageResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "reportId": { "type": "string", "description": "Report ID (existing one if already reported)." }, "alreadyReported": { "type": "boolean", "description": "True if the owner had already reported this message." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "reportId", "alreadyReported", "timestamp" ], "additionalProperties": false }, "Error": { "type": "object", "properties": { "error": { "type": "string", "description": "Stable machine-readable error code (e.g. error_api_key_invalid). Treat this, not the message, as the programmatic contract." }, "details": { "description": "Optional human-readable explanation. Often absent on auth/permission errors.", "x-ms-primary-error-message": true, "type": "string" } }, "required": [ "error" ], "additionalProperties": false, "description": "Standard API error response." }, "GameMatch": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "$ref": "#/components/schemas/MatchStatus" }, "gameMode": { "type": "string", "description": "Game mode identifier (from the match's gameModeId)." }, "bestOf": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of maps in the series (1, 3, 5, or 7)." }, "creatorTeam": { "anyOf": [ { "$ref": "#/components/schemas/Team" }, { "type": "null" } ] }, "acceptedTeam": { "anyOf": [ { "$ref": "#/components/schemas/Team" }, { "type": "null" } ] }, "creatorTeamScore": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "acceptedTeamScore": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scheduledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Scheduled start time (ISO 8601)." }, "startedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Actual start time (ISO 8601)." }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Completion time (ISO 8601)." }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Creation time (ISO 8601)." } }, "required": [ "id", "status", "gameMode", "bestOf", "creatorTeam", "acceptedTeam", "creatorTeamScore", "acceptedTeamScore", "scheduledAt", "startedAt", "completedAt", "createdAt" ], "additionalProperties": false, "description": "Match as returned by the game-developer endpoints (includes scores, omits the game object)." }, "MatchStatus": { "type": "string", "enum": [ "PENDING", "ACCEPTED", "READY", "IN_PROGRESS", "COMPLETED", "CANCELLED", "DISPUTED", "FORFEITED" ], "description": "Lifecycle status of a match." }, "Team": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "name": { "type": "string", "description": "Team name." }, "tag": { "type": "string", "description": "Team tag (short identifier)." }, "avatarUrl": { "description": "Team avatar URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "name", "tag" ], "additionalProperties": false, "description": "A team participating in a match." }, "GameMatchDetailResponse": { "type": "object", "properties": { "match": { "$ref": "#/components/schemas/GameMatchDetail" }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "match", "timestamp" ], "additionalProperties": false, "description": "Envelope for GET /game/matches/{matchId}: the match plus a response timestamp." }, "GameMatchDetail": { "type": "object", "properties": { "id": { "type": "string" }, "gameId": { "type": "string", "description": "Game ID the match belongs to." }, "gameMode": { "type": "string", "description": "Game mode identifier (from the match's gameModeId)." }, "status": { "$ref": "#/components/schemas/MatchStatus" }, "bestOf": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of maps in the series (1, 3, 5, or 7)." }, "creatorTeam": { "anyOf": [ { "$ref": "#/components/schemas/GameDetailTeam" }, { "type": "null" } ] }, "acceptedTeam": { "anyOf": [ { "$ref": "#/components/schemas/GameDetailTeam" }, { "type": "null" } ] }, "creatorTeamScore": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "acceptedTeamScore": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "winnerTeamId": { "description": "Winning team ID once the match completes.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "loserTeamId": { "description": "Losing team ID once the match completes.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "scheduledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Scheduled start time (ISO 8601)." }, "startedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Actual start time (ISO 8601)." }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Completion time (ISO 8601)." }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Creation time (ISO 8601)." }, "leagueId": { "description": "League this match belongs to, if any (SP-7 league wave).", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "leagueSeasonId": { "description": "League season this match belongs to, if any.", "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "gameId", "gameMode", "status", "bestOf", "creatorTeam", "acceptedTeam", "creatorTeamScore", "acceptedTeamScore", "scheduledAt", "startedAt", "completedAt", "createdAt" ], "additionalProperties": false, "description": "Detailed match payload returned inside the game-developer match-detail response." }, "GameDetailTeam": { "type": "object", "properties": { "_id": { "type": "string", "description": "Team ID." }, "name": { "type": "string", "description": "Team name." }, "tag": { "type": "string", "description": "Team tag (short identifier)." } }, "required": [ "_id", "name", "tag" ], "additionalProperties": false, "description": "A team as embedded in the game-developer match-detail response ({ _id, name, tag })." }, "GameForfeitResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string", "description": "ID of the forfeited match." }, "forfeitedByTeamId": { "type": "string", "description": "ID of the team that forfeited." }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "success", "matchId", "forfeitedByTeamId", "timestamp" ], "additionalProperties": false, "description": "Result of a successful match forfeit." }, "GamePlayerStatsResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Index of the map whose stats were updated." }, "action": { "type": "string", "description": "Operation performed, always \"updated\" on success." } }, "required": [ "success", "mapIndex", "action" ], "additionalProperties": false, "description": "Result of a successful player-stats update." }, "GameMatchRostersResponse": { "type": "object", "properties": { "creatorTeamId": { "type": "string", "description": "ID of the team that created the match." }, "acceptedTeamId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ID of the team that accepted the match, or null if unaccepted." }, "creatorRoster": { "type": "array", "items": { "$ref": "#/components/schemas/GameRosterPlayer" }, "description": "Players on the creator team." }, "acceptedRoster": { "type": "array", "items": { "$ref": "#/components/schemas/GameRosterPlayer" }, "description": "Players on the accepted team (empty when unaccepted)." }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "creatorTeamId", "acceptedTeamId", "creatorRoster", "acceptedRoster", "timestamp" ], "additionalProperties": false, "description": "Team rosters for a match, grouped by creator and accepted team." }, "GameRosterPlayer": { "type": "object", "properties": { "userId": { "type": "string", "description": "Player's user ID." }, "teamId": { "type": "string", "description": "ID of the team the player belongs to." }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Player's username, or null if unset." }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Player's display name, or null if unset." }, "isCheckedIn": { "type": "boolean", "description": "Whether the player has checked in for the match." } }, "required": [ "userId", "teamId", "username", "name", "isCheckedIn" ], "additionalProperties": false, "description": "A single player entry on a match roster." }, "GameScoresResponse": { "type": "object", "properties": { "scores": { "type": "array", "items": { "$ref": "#/components/schemas/GameScore" }, "description": "All recorded map scores for the match." }, "seriesScore": { "$ref": "#/components/schemas/GameSeriesScore" }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "scores", "seriesScore", "timestamp" ], "additionalProperties": false, "description": "All map scores for a match plus the aggregate series tally." }, "GameScore": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based index of the map within the series." }, "mapId": { "type": "string", "description": "Identifier of the map that was played." }, "creatorTeamScore": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Score for the creator team." }, "opponentTeamScore": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Score for the opponent (accepted) team." }, "scoreStatus": { "type": "string", "description": "Confirmation state: \"CONFIRMED\" or \"PENDING\"." }, "playerStats": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, { "type": "null" } ], "description": "Per-player stats keyed by user ID, or null when none recorded." }, "submittedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "When the score was submitted (ISO 8601)." }, "confirmedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "When the score was confirmed (ISO 8601)." } }, "required": [ "mapIndex", "mapId", "creatorTeamScore", "opponentTeamScore", "scoreStatus", "playerStats", "submittedAt", "confirmedAt" ], "additionalProperties": false, "description": "A single map score as returned when reading scores." }, "GameSeriesScore": { "type": "object", "properties": { "creatorMapWins": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Confirmed map wins for the creator team." }, "opponentMapWins": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Confirmed map wins for the opponent team." } }, "required": [ "creatorMapWins", "opponentMapWins" ], "additionalProperties": false, "description": "Aggregate map-win tally across the series." }, "GameBatchScoresResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "True only when every submitted map score was confirmed." }, "submitted": { "type": "array", "items": { "$ref": "#/components/schemas/GameBatchScoreResult" }, "description": "Per-map results, in submission order." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of map scores that were confirmed." } }, "required": [ "success", "submitted", "count" ], "additionalProperties": false, "description": "Result of a batch map-score submission." }, "GameBatchScoreResult": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Index of the map this result refers to." }, "status": { "type": "string", "description": "Per-map outcome: \"confirmed\" on success, \"failed\" otherwise." }, "error": { "description": "Failure reason, present only when status is failed.", "type": "string" } }, "required": [ "mapIndex", "status" ], "additionalProperties": false, "description": "Outcome for a single submitted map score." }, "GameSingleMapScoreResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Index of the map that was scored." }, "scoreStatus": { "type": "string", "description": "Confirmation state, always \"CONFIRMED\" on success." } }, "required": [ "success", "mapIndex", "scoreStatus" ], "additionalProperties": false, "description": "Result of submitting a single map score." }, "GameStatusUpdateResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string", "description": "ID of the updated match." }, "previousStatus": { "type": "string", "description": "Match status before the transition." }, "newStatus": { "type": "string", "description": "Match status after the transition." }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "success", "matchId", "previousStatus", "newStatus", "timestamp" ], "additionalProperties": false, "description": "Result of a successful match status transition." }, "GameBatchMatchScoresResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "True only when every submitted item was confirmed." }, "submitted": { "type": "array", "items": { "$ref": "#/components/schemas/GameBatchMatchScoreResult" }, "description": "Per-item results, in submission order." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of items that were confirmed." } }, "required": [ "success", "submitted", "count" ], "additionalProperties": false, "description": "Result of a multi-match batch map-score submission. Always returned with HTTP 200; inspect per-item status." }, "GameBatchMatchScoreResult": { "type": "object", "properties": { "matchId": { "type": "string", "description": "Match ID this result refers to." }, "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Index of the map this result refers to." }, "status": { "type": "string", "description": "Per-item outcome: \"confirmed\" on success, \"failed\" otherwise." }, "error": { "description": "Bare machine-readable error code (e.g. error_game_scope_mismatch), present only when status is failed. Never the raw message.", "type": "string" } }, "required": [ "matchId", "mapIndex", "status" ], "additionalProperties": false, "description": "Outcome for a single (match, map) item in a multi-match batch." }, "GameCreateMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string", "description": "ID of the newly created match." }, "timestamp": { "type": "string", "description": "Server response time (ISO 8601)." } }, "required": [ "success", "matchId", "timestamp" ], "additionalProperties": false, "description": "Result of a successful game-originated match creation." }, "ApiGameCatalogResponse": { "type": "object", "properties": { "games": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGameCatalogEntry" } }, "objectives": { "type": "array", "items": { "$ref": "#/components/schemas/ApiObjective" } }, "timestamp": { "type": "string" } }, "required": [ "games", "objectives", "timestamp" ], "additionalProperties": false, "description": "Game catalog list response." }, "ApiGameCatalogEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "Static public game ID/slug." }, "convexId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Active Convex games-table ID, when available for match APIs." }, "nameKey": { "type": "string" }, "shortNameKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "descriptionKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "category": { "type": "string" }, "rulesLink": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "coverImage": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bannerImage": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "defaultTeamSize": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "hasCompetitiveMode": { "type": "boolean" }, "isComingSoon": { "type": "boolean" }, "isAvailableForMatchApi": { "type": "boolean" }, "modes": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGameMode" } }, "maps": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGameMap" } }, "playlists": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGamePlaylist" } }, "modeMapPools": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGameModeMapPool" } } }, "required": [ "id", "convexId", "nameKey", "shortNameKey", "descriptionKey", "category", "rulesLink", "coverImage", "bannerImage", "defaultTeamSize", "hasCompetitiveMode", "isComingSoon", "isAvailableForMatchApi", "modes", "maps", "playlists", "modeMapPools" ], "additionalProperties": false, "description": "Static public game catalog entry." }, "ApiGameMode": { "type": "object", "properties": { "id": { "type": "string" }, "nameKey": { "type": "string" }, "descriptionKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "shortName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rewardBonus": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "supportsDraftToggle": { "type": "boolean" }, "mapIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "nameKey", "descriptionKey", "image", "shortName", "rewardBonus", "supportsDraftToggle", "mapIds" ], "additionalProperties": false, "description": "Static game mode definition." }, "ApiGameMap": { "type": "object", "properties": { "id": { "type": "string" }, "nameKey": { "type": "string" }, "coverImage": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "minimapImage": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isReleased": { "type": "boolean" } }, "required": [ "id", "nameKey", "coverImage", "minimapImage", "isReleased" ], "additionalProperties": false, "description": "Static game map definition." }, "ApiGamePlaylist": { "type": "object", "properties": { "id": { "type": "string" }, "nameKey": { "type": "string" }, "descriptionKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "allowedGameModeIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "nameKey", "descriptionKey", "image", "allowedGameModeIds" ], "additionalProperties": false, "description": "Game-scoped playlist definition." }, "ApiGameModeMapPool": { "type": "object", "properties": { "modeId": { "type": "string" }, "mapIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "modeId", "mapIds" ], "additionalProperties": false, "description": "Game-scoped map pool for a single mode." }, "ApiObjective": { "type": "object", "properties": { "id": { "type": "string", "description": "Objective definition ID." }, "titleKey": { "type": "string", "description": "i18n key for the objective title." }, "descriptionKey": { "type": "string", "description": "i18n key for the objective description." }, "exp": { "type": "number", "minimum": 0, "description": "Experience awarded by this objective." }, "scope": { "type": "string", "description": "Objective completion scope." }, "completionRule": { "type": "string", "description": "Machine-readable completion rule." } }, "required": [ "id", "titleKey", "descriptionKey", "exp", "scope", "completionRule" ], "additionalProperties": false, "description": "Server-safe objective DTO. UI icon components are intentionally omitted." }, "ApiGamePlaylistsResponse": { "type": "object", "properties": { "game": { "$ref": "#/components/schemas/ApiGameCatalogEntry" }, "playlists": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGamePlaylist" } }, "timestamp": { "type": "string" } }, "required": [ "game", "playlists", "timestamp" ], "additionalProperties": false, "description": "Game-scoped playlist response." }, "OrganizationLeaderboardResponse": { "type": "object", "properties": { "organizations": { "type": "array", "items": { "$ref": "#/components/schemas/OrganizationLeaderboardEntry" } }, "sortBy": { "$ref": "#/components/schemas/LeaderboardSortBy" }, "gameSlug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "type": "string" } }, "required": [ "organizations", "sortBy", "gameSlug", "timestamp" ], "additionalProperties": false, "description": "Organization leaderboard response." }, "OrganizationLeaderboardEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "Organization ID." }, "rank": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "organization": { "$ref": "#/components/schemas/ApiOrganizationSummary" }, "stats": { "type": "object", "properties": { "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "winRate": { "type": "number", "minimum": 0, "maximum": 1 }, "experience": { "type": "number", "minimum": 0 }, "teamCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "matchesPlayed", "wins", "losses", "winRate", "experience", "teamCount" ], "additionalProperties": false }, "gameSlug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "rank", "organization", "stats" ], "additionalProperties": false, "description": "Organization leaderboard row." }, "ApiOrganizationSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Organization ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Organization name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" } }, "required": [ "id", "name" ], "additionalProperties": false, "description": "Small API-safe organization summary." }, "ProfileVisibility": { "type": "string", "enum": [ "public", "limited", "private" ], "description": "Public profile visibility setting." }, "LeaderboardRankResponse": { "type": "object", "properties": { "id": { "type": "string", "description": "Resolved entity ID." }, "rank": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ] }, "sortBy": { "$ref": "#/components/schemas/LeaderboardSortBy" }, "gameSlug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "type": "string" } }, "required": [ "id", "rank", "sortBy", "timestamp" ], "additionalProperties": false, "description": "Leaderboard rank lookup response." }, "PlayerLeaderboardResponse": { "type": "object", "properties": { "players": { "type": "array", "items": { "$ref": "#/components/schemas/PlayerLeaderboardEntry" } }, "sortBy": { "$ref": "#/components/schemas/LeaderboardSortBy" }, "timestamp": { "type": "string" } }, "required": [ "players", "sortBy", "timestamp" ], "additionalProperties": false, "description": "Player leaderboard response." }, "PlayerLeaderboardEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "User ID." }, "rank": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "user": { "$ref": "#/components/schemas/ApiUserProfile" }, "stats": { "$ref": "#/components/schemas/LeaderboardStats" } }, "required": [ "id", "rank", "user", "stats" ], "additionalProperties": false, "description": "Player leaderboard row." }, "ApiUserProfile": { "type": "object", "properties": { "id": { "type": "string", "description": "User ID." }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "User handle, when set." }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Display name, when set." }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Avatar image URL, when set." }, "bannerUrl": { "description": "Banner image URL, when set.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isVerified": { "type": "boolean" }, "bio": { "description": "Public profile bio.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" }, "createdAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "username", "name", "avatarUrl", "visibility", "createdAt" ], "additionalProperties": false, "description": "API-safe public user profile." }, "LeaderboardStats": { "type": "object", "properties": { "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "winRate": { "type": "number", "minimum": 0, "maximum": 1 }, "experience": { "type": "number", "minimum": 0 } }, "required": [ "matchesPlayed", "wins", "losses", "winRate", "experience" ], "additionalProperties": false, "description": "Aggregate stats used for leaderboard ranking." }, "TeamLeaderboardResponse": { "type": "object", "properties": { "teams": { "type": "array", "items": { "$ref": "#/components/schemas/TeamLeaderboardEntry" } }, "sortBy": { "$ref": "#/components/schemas/LeaderboardSortBy" }, "gameSlug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "type": "string" } }, "required": [ "teams", "sortBy", "gameSlug", "timestamp" ], "additionalProperties": false, "description": "Team leaderboard response." }, "TeamLeaderboardEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "rank": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "team": { "$ref": "#/components/schemas/ApiTeamSummary" }, "stats": { "$ref": "#/components/schemas/LeaderboardStats" }, "gameSlug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "rank", "team", "stats" ], "additionalProperties": false, "description": "Team leaderboard row." }, "ApiTeamSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Team name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" } }, "required": [ "id", "name" ], "additionalProperties": false, "description": "Small API-safe team summary." }, "LeagueSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "League ID." }, "name": { "type": "string", "description": "League display name." }, "slug": { "type": "string", "description": "URL-friendly league identifier." }, "description": { "type": "string", "description": "League description." }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "League avatar image URL." }, "bannerUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "League banner image URL." }, "isVerified": { "type": "boolean", "description": "Whether the league is verified." }, "isFeatured": { "type": "boolean", "description": "Whether the league is featured." }, "games": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Games associated with the league." }, "teamCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of teams in the league." }, "seasonStatus": { "type": "string", "enum": [ "active", "upcoming", "none" ], "description": "Aggregate season state across the league's games." }, "createdAt": { "type": "number", "description": "Creation timestamp (epoch milliseconds)." }, "status": { "description": "League status.", "type": "string" } }, "required": [ "id", "name", "slug", "description", "avatarUrl", "bannerUrl", "isVerified", "isFeatured", "games", "teamCount", "seasonStatus", "createdAt" ], "additionalProperties": false, "description": "Summary view of a league for discovery results." }, "LeagueProfileResponse": { "type": "object", "properties": { "league": { "$ref": "#/components/schemas/LeagueProfile" }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "league", "timestamp" ], "additionalProperties": false, "description": "League profile response envelope." }, "LeagueProfile": { "type": "object", "properties": { "id": { "type": "string", "description": "League ID." }, "name": { "type": "string", "description": "League display name." }, "slug": { "type": "string", "description": "URL-friendly league identifier." }, "description": { "type": "string", "description": "League description." }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "League avatar image URL." }, "bannerUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "League banner image URL." }, "status": { "type": "string", "description": "League status (e.g. active, inactive)." }, "isVerified": { "type": "boolean", "description": "Whether the league is verified." }, "isFeatured": { "type": "boolean", "description": "Whether the league is featured." }, "teamCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of teams in the league." }, "staffCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of staff members." }, "games": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Games associated with the league." }, "activeSeasons": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Currently active seasons." }, "socials": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Social media links." }, "createdAt": { "type": "number", "description": "Creation timestamp (epoch milliseconds)." } }, "required": [ "id", "name", "slug", "description", "avatarUrl", "bannerUrl", "status", "isVerified", "isFeatured", "teamCount", "staffCount", "games", "activeSeasons", "socials", "createdAt" ], "additionalProperties": false, "description": "Public profile for a single league." }, "LeagueActivityFeedResponse": { "type": "object", "properties": { "activities": { "type": "array", "items": {}, "description": "Activity entries, newest first. Each carries id, action, actorId, targetType, targetId, metadata and createdAt. Normal actions include actorName; actions taken by TeamBattles Platform Staff under audited elevation suppress actorName and set isPlatformStaff: true, keeping only actorId." }, "nextCursor": { "type": "string" }, "hasMore": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "activities", "nextCursor", "hasMore", "timestamp" ], "additionalProperties": false, "description": "A paginated league activity feed." }, "AnnounceLeagueResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "notified": { "type": "number", "description": "Number of members notified by the announcement." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "notified", "timestamp" ], "additionalProperties": false }, "LeagueApplyEligibility": { "type": "object", "properties": { "eligibility": { "type": "object", "properties": { "isAuthed": { "type": "boolean" }, "hasApprovedTeamHere": { "type": "boolean" }, "pendingTeams": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} } }, "eligibleTeams": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} } } }, "required": [ "isAuthed", "hasApprovedTeamHere", "pendingTeams", "eligibleTeams" ], "additionalProperties": false, "description": "API key owner's apply-to-join eligibility." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "eligibility", "timestamp" ], "additionalProperties": false, "description": "League application eligibility." }, "LeagueBans": { "type": "object", "properties": { "bans": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Enriched team ban records with computed status." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of bans returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "bans", "count", "timestamp" ], "additionalProperties": false, "description": "Team bans for a league." }, "RevokeBanResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CreateBanResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "banId": { "type": "string", "description": "Created league ban ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "banId", "timestamp" ], "additionalProperties": false }, "UpdateLeagueBrandingResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ClearCooldownResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UpdateLeagueCooldownConfigResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "IssueCooldownResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "cooldownId": { "type": "string", "description": "League member cooldown ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "cooldownId", "timestamp" ], "additionalProperties": false }, "LeagueDashboardStatsResponse": { "type": "object", "properties": { "stats": { "type": "object", "properties": { "teamCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "pendingApplications": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "activeSeasons": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "openTickets": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "teamCount", "pendingApplications", "activeSeasons", "openTickets" ], "additionalProperties": false }, "timestamp": { "type": "string" } }, "required": [ "stats", "timestamp" ], "additionalProperties": false, "description": "Aggregate league admin dashboard statistics." }, "LeagueDisplayRules": { "type": "object", "properties": { "displayRules": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Display rule documents for the league game." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of display rules returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "displayRules", "count", "timestamp" ], "additionalProperties": false, "description": "League display rules." }, "RemoveDisplayRuleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ReorderDisplayRulesResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UpsertDisplayRuleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "displayRuleId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "displayRuleId", "timestamp" ], "additionalProperties": false }, "LeagueGames": { "type": "object", "properties": { "games": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Games configured for the league." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of configured games returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "games", "count", "timestamp" ], "additionalProperties": false, "description": "Games configured for a league." }, "RemoveLeagueGameResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ToggleLeagueGameResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "LeagueGameWriteResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "LeagueMembers": { "type": "object", "properties": { "members": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Enriched league staff member records." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of members returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "members", "count", "timestamp" ], "additionalProperties": false, "description": "Staff members of a league." }, "RemoveLeagueMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UpdateLeagueMemberRoleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "AddLeagueMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "TransferLeagueOwnershipResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "LeaguePenalties": { "type": "object", "properties": { "penalties": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Enriched penalty records (empty when type is cooldowns)." }, "cooldowns": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Enriched member cooldown records (empty when type is penalties)." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Combined number of penalties and cooldowns returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "penalties", "cooldowns", "count", "timestamp" ], "additionalProperties": false, "description": "Penalties and cooldowns for a league." }, "CreatePenaltyResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "penaltyId": { "type": "string", "description": "Created league penalty ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "penaltyId", "timestamp" ], "additionalProperties": false }, "UpdatePointsConfigResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "configId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "configId", "timestamp" ], "additionalProperties": false }, "LeagueRules": { "type": "object", "properties": { "rules": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Game rules document for the league + game, or null if unset." }, "pointsConfig": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Points configuration document for the league + game, or null if unset." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "rules", "pointsConfig", "timestamp" ], "additionalProperties": false, "description": "Game rules and points config for a league." }, "ApplyRuleTemplateResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "rulesId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "rulesId", "timestamp" ], "additionalProperties": false }, "RuleWriteResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "rulesId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "rulesId", "timestamp" ], "additionalProperties": false }, "LeagueSeasonOptions": { "type": "object", "properties": { "seasons": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Season selector options for a league game." }, "defaultSeasonId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Recommended default option." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "seasons", "defaultSeasonId", "timestamp" ], "additionalProperties": false, "description": "Season selector options." }, "LeagueSeasons": { "type": "object", "properties": { "seasons": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Season documents for the league." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of seasons returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "seasons", "count", "timestamp" ], "additionalProperties": false, "description": "Seasons for a league." }, "DeleteLeagueSeasonResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "LeagueSeason": { "type": "object", "properties": { "season": { "type": "object", "properties": {}, "additionalProperties": {}, "description": "The requested league season." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "season", "timestamp" ], "additionalProperties": false, "description": "Single league season response." }, "ActivateLeagueSeasonResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CompleteLeagueSeasonResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CreateSeasonResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "seasonId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "seasonId", "timestamp" ], "additionalProperties": false }, "LeagueSettingsResponse": { "type": "object", "properties": { "league": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "timestamp": { "type": "string" } }, "required": [ "league", "timestamp" ], "additionalProperties": false, "description": "Full league settings visible to league admins." }, "SetLeagueEnabledResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "RequestLeagueShutdownResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "LeagueStandings": { "type": "object", "properties": { "standings": { "type": "array", "items": { "type": "object", "properties": { "rank": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "1-based standings position." } }, "required": [ "rank" ], "additionalProperties": {} }, "description": "Approved teams with season stats, ordered by standings position. Each item is a team-with-stats document plus a computed rank." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of teams returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "standings", "count", "timestamp" ], "additionalProperties": false, "description": "League standings for a season." }, "ApproveLeagueTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "DenyLeagueTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "RemoveLeagueTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UpdateLeagueTicketResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "EscalateLeagueTicketResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ReplyLeagueTicketResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CreateLeagueTicketResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "ticketId": { "type": "string", "description": "Created ticket ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "ticketId", "timestamp" ], "additionalProperties": false }, "LeagueTemplates": { "type": "object", "properties": { "templates": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Rule templates visible to the API key owner." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of templates returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "templates", "count", "timestamp" ], "additionalProperties": false, "description": "League rule templates." }, "ApiMatchDetailResponse": { "type": "object", "properties": { "match": { "$ref": "#/components/schemas/ApiMatchDetail" }, "timestamp": { "type": "string" } }, "required": [ "match", "timestamp" ], "additionalProperties": false, "description": "SP-2 match detail response." }, "ApiMatchDetail": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "$ref": "#/components/schemas/MatchStatus" }, "publishStatus": { "type": "string" }, "game": { "$ref": "#/components/schemas/Game" }, "gameMode": { "type": "string" }, "matchType": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "platform": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "region": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "creatorTeam": { "anyOf": [ { "$ref": "#/components/schemas/ApiMatchTeam" }, { "type": "null" } ] }, "acceptedTeam": { "anyOf": [ { "$ref": "#/components/schemas/ApiMatchTeam" }, { "type": "null" } ] }, "challengedTeam": { "anyOf": [ { "$ref": "#/components/schemas/ApiMatchTeam" }, { "type": "null" } ] }, "bestOf": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "teamSize": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "selectedMaps": { "type": "array", "items": { "type": "string" } }, "selectedObjectives": { "type": "array", "items": { "type": "string" } }, "winnerTeamId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "scheduledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "startedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "leagueId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "leagueSeasonId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "status", "publishStatus", "game", "gameMode", "creatorTeam", "acceptedTeam", "bestOf", "teamSize", "selectedMaps", "selectedObjectives", "winnerTeamId", "scheduledAt", "startedAt", "completedAt", "createdAt" ], "additionalProperties": false, "description": "Participant-gated SP-2 match detail. Lobby codes are intentionally omitted." }, "Game": { "type": "object", "properties": { "id": { "type": "string", "description": "Game ID." }, "nameKey": { "type": "string", "description": "Game name key for i18n lookup." } }, "required": [ "id", "nameKey" ], "additionalProperties": false, "description": "Game definition." }, "ApiMatchTeam": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "name": { "type": "string", "description": "Team name." }, "tag": { "type": "string", "description": "Team tag (short identifier)." }, "avatarUrl": { "description": "Team avatar URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "score": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] } }, "required": [ "id", "name", "tag" ], "additionalProperties": false, "description": "Team summary embedded in SP-2 match reads." }, "AcceptMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "acceptanceId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "acceptanceId", "timestamp" ], "additionalProperties": false }, "ApproveAcceptanceResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "DeclineAcceptanceResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UpdateAttendanceResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "reclaimedSpot": { "type": "boolean" }, "replacedBy": { "type": "string" }, "message": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CancelMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "matchId", "timestamp" ], "additionalProperties": false }, "AcceptChallengeResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "RefuseChallengeResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ChatMessage": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "senderUserId": { "type": "string" }, "senderUsername": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "teamId": { "type": "string" }, "replyToId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "content", "senderUserId", "senderUsername", "teamId", "replyToId", "createdAt" ], "additionalProperties": false }, "SendChatMessageResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "messageId": { "type": "string", "description": "Created message ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "messageId", "timestamp" ], "additionalProperties": false }, "ForfeitMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "matchId", "timestamp" ], "additionalProperties": false }, "UpdateLobbyCodeResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "lobbyCode": { "type": "string" }, "statusChanged": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "success", "lobbyCode", "statusChanged", "timestamp" ], "additionalProperties": false }, "ApiMatchPlayersResponse": { "type": "object", "properties": { "matchId": { "type": "string" }, "players": { "type": "array", "items": { "$ref": "#/components/schemas/ApiMatchPlayer" } }, "timestamp": { "type": "string" } }, "required": [ "matchId", "players", "timestamp" ], "additionalProperties": false, "description": "SP-2 match player rows response." }, "ApiMatchPlayer": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "teamId": { "type": "string" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rosterType": { "type": "string", "enum": [ "ACTIVE", "BENCH" ] }, "attendanceStatus": { "type": "string", "enum": [ "ATTENDING", "NOT_ATTENDING", "TENTATIVE" ] }, "isCheckedIn": { "type": "boolean" }, "checkedInAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "userId", "teamId", "username", "name", "rosterType", "attendanceStatus", "isCheckedIn", "checkedInAt" ], "additionalProperties": false, "description": "Player row for a participant-gated match." }, "PublishMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "MarkMatchReadyResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchReady": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "success", "matchReady", "timestamp" ], "additionalProperties": false }, "MapScores": { "type": "object", "properties": { "scores": { "type": "array", "items": { "$ref": "#/components/schemas/MapScoreItem" } }, "seriesScore": { "type": "object", "properties": { "creatorMapWins": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "opponentMapWins": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "creatorMapWins", "opponentMapWins" ], "additionalProperties": false }, "timestamp": { "type": "string", "description": "Response timestamp (ISO 8601)." } }, "required": [ "scores", "seriesScore", "timestamp" ], "additionalProperties": false, "description": "All map scores for a match with a series summary." }, "MapScoreItem": { "type": "object", "properties": { "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "mapId": { "type": "string" }, "creatorTeamScore": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "opponentTeamScore": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "screenshotUrls": { "type": "array", "items": { "type": "string" } }, "scoreStatus": { "type": "string", "description": "CONFIRMED or PENDING." }, "submittedBy": { "anyOf": [ { "$ref": "#/components/schemas/ScoreSubmitter" }, { "type": "null" } ] }, "confirmedBy": { "anyOf": [ { "$ref": "#/components/schemas/ScoreConfirmer" }, { "type": "null" } ] }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Creation time (ISO 8601)." } }, "required": [ "mapIndex", "mapId", "creatorTeamScore", "opponentTeamScore", "screenshotUrls", "scoreStatus", "submittedBy", "confirmedBy", "createdAt" ], "additionalProperties": false, "description": "A single map's score entry." }, "ScoreSubmitter": { "type": "object", "properties": { "userId": { "type": "string" }, "teamId": { "type": "string" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "userId", "teamId", "name" ], "additionalProperties": false, "description": "Identity of the captain who submitted a score." }, "ScoreConfirmer": { "type": "object", "properties": { "userId": { "type": "string" }, "teamId": { "type": "string" }, "confirmedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Confirmation time (ISO 8601)." } }, "required": [ "userId", "teamId", "confirmedAt" ], "additionalProperties": false, "description": "Identity of the captain who confirmed a score." }, "ScoreSubmissionResult": { "type": "object", "properties": { "success": { "type": "boolean" }, "action": { "type": "string", "description": "Action performed, e.g. \"submitted\" or \"confirmed\"." }, "mapIndex": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based map index that was affected." }, "scoreStatus": { "type": "string", "description": "Resulting score status, e.g. PENDING or CONFIRMED." } }, "required": [ "success", "action", "mapIndex", "scoreStatus" ], "additionalProperties": false, "description": "Result of submitting or confirming a map score." }, "StartMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "CreateMatchResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "matchId": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "success", "matchId", "timestamp" ], "additionalProperties": false }, "MatchDiscoverPage": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ApiMatchDetail" } }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hasMore": { "type": "boolean" }, "timestamp": { "type": "string" } }, "required": [ "data", "nextCursor", "hasMore", "timestamp" ], "additionalProperties": false, "description": "SP-2 open-match discovery page." }, "CreateOrgResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "id": { "type": "string", "description": "The created organization ID." }, "slug": { "type": "string", "description": "The created organization slug." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "id", "slug", "timestamp" ], "additionalProperties": false }, "DeleteOrgResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ApiOrganizationProfile": { "type": "object", "properties": { "id": { "type": "string", "description": "Organization ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Organization name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bannerUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isVerified": { "type": "boolean" }, "isMember": { "type": "boolean" }, "memberCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "teamCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "draws": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "createdAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "name", "isMember", "createdAt" ], "additionalProperties": false, "description": "API-safe organization profile." }, "UpdateOrgResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "UserMatch": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "$ref": "#/components/schemas/MatchStatus" }, "game": { "$ref": "#/components/schemas/Game" }, "gameMode": { "type": "string", "description": "Game mode (e.g. HARDPOINT, SEARCH_AND_DESTROY)." }, "creatorTeam": { "anyOf": [ { "$ref": "#/components/schemas/Team" }, { "type": "null" } ] }, "acceptedTeam": { "anyOf": [ { "$ref": "#/components/schemas/Team" }, { "type": "null" } ] }, "scheduledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Scheduled start time (ISO 8601)." }, "startedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Actual start time (ISO 8601)." }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Completion time (ISO 8601)." }, "bestOf": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of maps in the series (1, 3, 5, or 7)." } }, "required": [ "id", "status", "game", "gameMode", "creatorTeam", "acceptedTeam", "scheduledAt", "startedAt", "completedAt", "bestOf" ], "additionalProperties": false, "description": "Match as returned by the user/team/org match-listing endpoints." }, "ApiMember": { "type": "object", "properties": { "id": { "type": "string", "description": "Membership row ID." }, "user": { "$ref": "#/components/schemas/ApiUserProfile" }, "role": { "type": "string", "description": "Role label within the team or organization." }, "joinedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "user", "role", "joinedAt" ], "additionalProperties": false, "description": "API-safe team or organization member." }, "AddOrgMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "RemoveOrgMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "SetOrgMemberRoleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "TransferOrgOwnershipResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ApiOrganizationStats": { "type": "object", "properties": { "organizationId": { "type": "string" }, "teams": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "members": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "winRate": { "type": "number", "minimum": 0, "maximum": 1 } }, "required": [ "organizationId", "teams", "members", "matchesPlayed", "wins", "losses", "winRate" ], "additionalProperties": false, "description": "API-safe organization aggregate stats." }, "ApiStrategyEnvelope": { "type": "object", "properties": { "strategy": { "$ref": "#/components/schemas/ApiStrategy" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "strategy", "timestamp" ], "additionalProperties": false, "description": "Strategy plus a response timestamp." }, "ApiStrategy": { "type": "object", "properties": { "id": { "type": "string", "description": "Strategy ID." }, "ownerId": { "type": "string", "description": "Owning user ID." }, "name": { "type": "string", "description": "Strategy name." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Author description, when set." }, "game": { "type": "string", "description": "Game slug the strategy targets." }, "mapId": { "type": "string", "description": "Built-in map slug, or the sentinel \"__custom\" for a custom map." }, "visibility": { "$ref": "#/components/schemas/StrategyVisibility" }, "shareSlug": { "type": "string", "description": "Public share slug." }, "mapRotation": { "type": "number", "description": "Map render orientation in degrees (0, 90, 180, or 270)." }, "playbackLoop": { "type": "boolean", "description": "Whether frame playback wraps from the last stage to the first." }, "stages": { "type": "array", "items": { "$ref": "#/components/schemas/ApiStrategyStage" } }, "stageCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "previewUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Freshly signed preview image URL, when a preview has been rendered." }, "createdAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] }, "updatedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "ownerId", "name", "description", "game", "mapId", "visibility", "shareSlug", "mapRotation", "playbackLoop", "stages", "stageCount", "previewUrl", "createdAt", "updatedAt" ], "additionalProperties": false, "description": "API-safe shareable strategy." }, "StrategyVisibility": { "type": "string", "enum": [ "private", "unlisted", "public" ], "description": "Strategy share visibility setting." }, "ApiStrategyStage": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage id within the strategy." }, "label": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Author stage label, when set." }, "durationMs": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Stage playback duration in milliseconds." } }, "required": [ "id", "label", "durationMs" ], "additionalProperties": false, "description": "A single playback stage of a strategy." }, "ApiStrategyShapesEnvelope": { "type": "object", "properties": { "shapes": { "type": "array", "items": { "$ref": "#/components/schemas/ApiStrategyShape" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "shapes", "count", "timestamp" ], "additionalProperties": false, "description": "Strategy shapes, count, and a response timestamp." }, "ApiStrategyShape": { "type": "object", "properties": { "id": { "type": "string", "description": "Shape row ID." }, "shapeId": { "type": "string", "description": "Stable client-side shape id." }, "stageId": { "type": "string", "description": "Stage this shape belongs to." }, "type": { "type": "string", "enum": [ "ink", "line", "arrow", "rect", "ellipse", "polygon", "text", "token", "image" ], "description": "Shape primitive type." }, "layer": { "type": "string", "enum": [ "drawing", "tokens" ], "description": "Canvas layer the shape renders on." }, "zIndex": { "type": "number", "description": "Stacking order within its layer." }, "data": { "description": "Opaque shape payload consumed by the canvas renderer." }, "updatedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "shapeId", "stageId", "type", "layer", "zIndex", "data", "updatedAt" ], "additionalProperties": false, "description": "API-safe strategy shape. Hidden working shapes are omitted from responses." }, "ApiBatchStreamStatusEnvelope": { "type": "object", "properties": { "statuses": { "type": "array", "items": { "$ref": "#/components/schemas/ApiBatchStreamStatus" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "statuses", "count", "timestamp" ], "additionalProperties": false, "description": "Batch live-status results plus a response timestamp. Users not visible to the caller are omitted." }, "ApiBatchStreamStatus": { "type": "object", "properties": { "id": { "type": "string", "description": "User ID." }, "isLive": { "type": "boolean" }, "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/StreamPlatform" } } }, "required": [ "id", "isLive", "platforms" ], "additionalProperties": false, "description": "Compact live-status row returned by the batch endpoint." }, "StreamPlatform": { "type": "string", "enum": [ "TWITCH", "YOUTUBE", "KICK" ], "description": "Supported streaming platform." }, "CreateTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "id": { "type": "string", "description": "The created team ID." }, "slug": { "type": "string", "description": "The created team slug." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "id", "slug", "timestamp" ], "additionalProperties": false }, "DisbandTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "ApiTeamProfile": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Team name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bannerUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "gameId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "organizationId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isMember": { "type": "boolean" }, "memberCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "draws": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "experience": { "type": "number", "minimum": 0 }, "createdAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "name", "isMember", "createdAt" ], "additionalProperties": false, "description": "API-safe team profile." }, "UpdateTeamResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "TransferTeamCaptaincyResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "RemoveTeamMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "SetTeamMemberRoleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false }, "TicketSummary": { "type": "object", "properties": { "id": { "type": "string" }, "ticketNumber": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "subject": { "type": "string" }, "category": { "type": "string" }, "status": { "type": "string", "enum": [ "open", "in_progress", "awaiting_response", "resolved", "closed" ] }, "priority": { "type": "string", "enum": [ "low", "medium", "high", "urgent" ] }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "updatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "ticketNumber", "subject", "category", "status", "priority", "createdAt", "updatedAt" ], "additionalProperties": false }, "CreateTicketResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "ticketId": { "type": "string", "description": "Created ticket ID." }, "ticketNumber": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Human-facing sequential ticket number." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "ticketId", "ticketNumber", "timestamp" ], "additionalProperties": false }, "TicketDetail": { "type": "object", "properties": { "id": { "type": "string" }, "ticketNumber": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "subject": { "type": "string" }, "description": { "type": "string" }, "category": { "type": "string" }, "status": { "type": "string", "enum": [ "open", "in_progress", "awaiting_response", "resolved", "closed" ] }, "priority": { "type": "string", "enum": [ "low", "medium", "high", "urgent" ] }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "updatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "resolvedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "closedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "isSystem": { "type": "boolean" }, "isOwnMessage": { "type": "boolean" }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "content", "isSystem", "isOwnMessage", "createdAt" ], "additionalProperties": false } }, "timestamp": { "type": "string" } }, "required": [ "id", "ticketNumber", "subject", "description", "category", "status", "priority", "createdAt", "updatedAt", "resolvedAt", "closedAt", "messages", "timestamp" ], "additionalProperties": false }, "AddTicketMessageResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "messageId": { "type": "string", "description": "Created message ID." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "messageId", "timestamp" ], "additionalProperties": false }, "TournamentCreateResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "tournamentId": { "type": "string" }, "slug": { "type": "string", "description": "Derived from the name and de-duplicated server-side, so it is NOT predictable from the name you sent. Every other tournament endpoint resolves by this slug, never by `tournamentId`, so store it." }, "status": { "type": "string", "const": "DRAFT", "description": "Always DRAFT. A guaranteed post-condition, not an echo - createCore hard-codes it." }, "approvalStatus": { "type": "string", "const": "NOT_SUBMITTED", "description": "Always NOT_SUBMITTED. Call submit-for-approval next; the tournament is invisible to the public discovery surface until staff approve it." }, "timestamp": { "type": "string" } }, "required": [ "success", "tournamentId", "slug", "status", "approvalStatus", "timestamp" ], "additionalProperties": false, "description": "The newly created draft tournament." }, "TournamentProfileResponse": { "type": "object", "properties": { "tournament": { "$ref": "#/components/schemas/TournamentProfile" }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "tournament", "timestamp" ], "additionalProperties": false, "description": "Tournament profile response envelope." }, "TournamentProfile": { "type": "object", "properties": { "_id": { "type": "string", "description": "Tournament ID." }, "name": { "type": "string", "description": "Tournament display name." }, "slug": { "type": "string", "description": "URL-friendly tournament identifier." }, "format": { "$ref": "#/components/schemas/TournamentFormat" }, "status": { "$ref": "#/components/schemas/TournamentStatus" }, "approvalStatus": { "type": "string", "description": "Platform review state, independent of `status`." }, "visibility": { "type": "string", "description": "PUBLIC or UNLISTED." }, "isPubliclyListed": { "type": "boolean", "description": "Whether the tournament appears in discovery." }, "teamSize": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Players per participating team." }, "participantCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Current number of participants." }, "maxParticipants": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Participant cap." }, "bannerUrl": { "description": "Banner image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "logoUrl": { "description": "Logo image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "game": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Game summary, or null if the game row is missing." }, "host": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Host identity (user, org, or league), or null if unresolvable." }, "needsAttention": { "type": "boolean", "description": "Whether the tournament is non-terminal AND awaiting organizer action on approval." }, "viewerManagement": { "type": "object", "properties": {}, "additionalProperties": {}, "description": "The caller's standing on this tournament. `isManager` includes tournament moderators; `isAdmin` does not." } }, "required": [ "_id", "name", "slug", "format", "status", "approvalStatus", "visibility", "isPubliclyListed", "teamSize", "participantCount", "maxParticipants", "game", "host", "needsAttention", "viewerManagement" ], "additionalProperties": {}, "description": "Public profile for a single tournament. Manager-private review fields are present only for a caller who manages it." }, "TournamentActivityFeedResponse": { "type": "object", "properties": { "activities": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentActivityEntry" }, "description": "Activity entries newest first. Not cursor-paginated: this is a single `limit`-capped window over the most recent rows, so there is no way to page past the newest 100." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of entries returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "activities", "count", "timestamp" ], "additionalProperties": false, "description": "The tournament organizer activity feed." }, "TournamentActivityEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "Activity log row ID." }, "action": { "type": "string", "description": "Action identifier, e.g. registration_opened, participant_approved, invite_revoked. Open-ended: treat unrecognised values as informational rather than an error." }, "actor": { "anyOf": [ { "$ref": "#/components/schemas/TournamentActivityActor" }, { "type": "null" } ], "description": "The acting user, or null when the user row no longer resolves." }, "targetType": { "description": "Kind of row the action targeted, when the action names one.", "type": "string" }, "targetId": { "description": "ID of the targeted row.", "type": "string" }, "metadata": { "description": "Action-specific detail. Shape varies by `action`.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "createdAt": { "type": "number", "description": "Log time (epoch milliseconds)." } }, "required": [ "id", "action", "actor", "createdAt" ], "additionalProperties": false, "description": "One tournament activity log entry." }, "TournamentActivityActor": { "type": "object", "properties": { "id": { "type": "string", "description": "Actor's user ID." }, "username": { "description": "Username. Omitted when the action was taken by Platform Staff.", "type": "string" }, "name": { "description": "Display name. Omitted when the action was taken by Platform Staff.", "type": "string" }, "isPlatformStaff": { "description": "Present and true when a TeamBattles Platform Staff member took the action under audited elevation. username and name are suppressed in that case - only id is retained.", "type": "boolean", "const": true } }, "required": [ "id" ], "additionalProperties": false, "description": "The user who performed a logged tournament action. Platform Staff actions suppress username/name and set isPlatformStaff: true, keeping only the id." }, "TournamentApplicationsResponse": { "type": "object", "properties": { "applications": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentApplication" }, "description": "Participant rows in PENDING status only. Approved, denied, withdrawn, and disqualified entries are not applications and appear on the participants endpoint instead." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of applications returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "applications", "count", "timestamp" ], "additionalProperties": false, "description": "Pending tournament applications." }, "TournamentApplication": { "type": "object", "properties": { "id": { "type": "string", "description": "Participant ID of the pending application." }, "teamId": { "type": "string", "description": "Applying team's ID." }, "teamName": { "type": "string", "description": "Applying team's display name." }, "teamAvatarUrl": { "description": "Applying team's avatar URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "appliedByUserId": { "description": "User who submitted the application, when recorded.", "type": "string" }, "registeredAt": { "type": "number", "description": "Application time (epoch milliseconds)." } }, "required": [ "id", "teamId", "teamName", "registeredAt" ], "additionalProperties": false, "description": "A team application awaiting organizer review." }, "TournamentWriteAck": { "type": "object", "properties": { "success": { "type": "boolean", "const": true, "description": "Always true; failures are error responses." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "success", "timestamp" ], "additionalProperties": false, "description": "Acknowledgement returned by the tournament write endpoints whose backing operation has nothing to return - the organizer writes (endpoints 22-34), the team roster writes (40, 41), and the competitor self actions that neither mint nor resolve a row (38, 39, 44, 45, 47). Endpoints that mint a row answer with that row's id instead, and the two respond endpoints (42, 46) answer with the decision they recorded." }, "TournamentBracketResponse": { "type": "object", "properties": { "bracket": { "$ref": "#/components/schemas/TournamentBracket" }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "bracket", "timestamp" ], "additionalProperties": false, "description": "Tournament bracket response envelope." }, "TournamentBracket": { "type": "object", "properties": { "rounds": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Round documents, ordered by round number ascending." }, "nodes": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Bracket node documents (slots, results, and links)." }, "display": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "object", "properties": {}, "additionalProperties": {} }, "description": "Participant ID -> { name, avatarUrl, seed } display map." }, "disqualified": { "type": "array", "items": { "type": "string" }, "description": "Participant IDs currently disqualified." }, "grandFinalAdvantage": { "description": "Grand-final advantage rule, copied verbatim from the tournament's `formatConfig`. Absent only when the tournament carries no `formatConfig` at all. NOT display data: WIN_HEADSTART pre-credits grand-final slot 1 at generation time, so any client re-deriving a walkover score pair must apply this rule or it zeroes the credit out.", "$ref": "#/components/schemas/TournamentGrandFinalAdvantage" } }, "required": [ "rounds", "nodes", "display", "disqualified" ], "additionalProperties": false, "description": "Rounds, nodes, and participant display data." }, "TournamentGrandFinalAdvantage": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "NONE", "WIN_HEADSTART", "MAP_SELECTION", "BRACKET_RESET" ], "description": "Which advantage the winners-bracket champion carries into the grand final." }, "winHeadstart": { "description": "Map/game wins pre-credited to grand-final slot 1. Only meaningful when `type` is WIN_HEADSTART; a WIN_HEADSTART carrying no value pre-credits nothing.", "type": "number" } }, "required": [ "type" ], "additionalProperties": false, "description": "Grand-final advantage rule granted to the winners-bracket champion." }, "TournamentCancelResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "status": { "type": "string", "const": "CANCELLED", "description": "The lifecycle status this call set." }, "approvalStatus": { "type": "string", "enum": [ "NOT_SUBMITTED", "AWAITING_APPROVAL", "APPROVED", "REJECTED" ], "description": "The tournament's approval status as of this request's authorization snapshot. Cancelling does NOT touch it, so it is reported as an INDEPENDENT field: `CANCELLED` alongside `NOT_SUBMITTED` is a real, reachable pair, and any status projection you build must handle it rather than deriving one field from the other." }, "timestamp": { "type": "string" } }, "required": [ "success", "status", "approvalStatus", "timestamp" ], "additionalProperties": false, "description": "Result of cancelling a tournament." }, "TournamentOfferRespondResponse": { "type": "object", "properties": { "accepted": { "type": "boolean", "description": "Echoes the request's accept flag once the response has been recorded. An offer that turned out to be no longer actionable is a 409 rather than a false here - see the endpoint description." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "accepted", "timestamp" ], "additionalProperties": false, "description": "Outcome of accepting or declining a free-agent pickup offer." }, "TournamentFreeAgentsResponse": { "type": "object", "properties": { "freeAgents": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentFreeAgent" }, "description": "Free agents currently AVAILABLE in the pool." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of free agents returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "freeAgents", "count", "timestamp" ], "additionalProperties": false, "description": "The tournament free-agent pool." }, "TournamentFreeAgent": { "type": "object", "properties": { "id": { "type": "string", "description": "Free-agent row ID." }, "userId": { "type": "string", "description": "User ID of the free agent." }, "username": { "description": "Username.", "type": "string" }, "name": { "description": "Display name.", "type": "string" }, "avatarUrl": { "description": "Avatar image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "note": { "description": "Free-text note the agent supplied.", "type": "string" }, "createdAt": { "type": "number", "description": "Pool join time (epoch milliseconds)." }, "viewerOfferStatus": { "anyOf": [ { "type": "string", "const": "PENDING" }, { "type": "null" } ], "description": "PENDING when `viewerParticipantId` was supplied AND authorized AND that participant has an open offer to this agent; null otherwise. An unauthorized or stale `viewerParticipantId` fails soft to null rather than erroring." } }, "required": [ "id", "userId", "createdAt", "viewerOfferStatus" ], "additionalProperties": false, "description": "An available free agent." }, "TournamentInvitesResponse": { "type": "object", "properties": { "invites": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentInvite" }, "description": "Every invite row on the tournament in creation order, in all four states. Filter on `status` for the outstanding ones." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of invites returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "invites", "count", "timestamp" ], "additionalProperties": false, "description": "Tournament team invites." }, "TournamentInvite": { "type": "object", "properties": { "id": { "type": "string", "description": "Invite ID." }, "teamId": { "type": "string", "description": "Invited team's ID." }, "teamName": { "type": "string", "description": "Invited team's display name." }, "teamAvatarUrl": { "description": "Invited team's avatar URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "$ref": "#/components/schemas/TournamentInviteStatus" }, "invitedByUserId": { "type": "string", "description": "Organizer who sent the invite." }, "createdAt": { "type": "number", "description": "Invite time (epoch milliseconds)." }, "respondedAt": { "description": "Response time (epoch milliseconds). Absent while PENDING.", "type": "number" } }, "required": [ "id", "teamId", "teamName", "status", "invitedByUserId", "createdAt" ], "additionalProperties": false, "description": "A team invite issued by the organizer." }, "TournamentInviteStatus": { "type": "string", "enum": [ "PENDING", "ACCEPTED", "DECLINED", "REVOKED" ], "description": "State of a tournament team invite." }, "TournamentInviteRespondResponse": { "type": "object", "properties": { "accepted": { "type": "boolean", "description": "Echoes the request's accept flag once the response has been recorded." }, "participantId": { "description": "The participant row the acceptance created or reused. Present only when accepted is true; store it, because check-in and withdraw are keyed by it.", "type": "string" }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "accepted", "timestamp" ], "additionalProperties": false, "description": "Outcome of accepting or declining a tournament invite." }, "TournamentLeaguePointsResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "leaguePointsEnabled": { "type": "boolean" }, "placementCount": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "Number of rows in the stored curve, or null when no explicit curve is stored and the platform default applies." }, "timestamp": { "type": "string" } }, "required": [ "success", "leaguePointsEnabled", "placementCount", "timestamp" ], "additionalProperties": false, "description": "The league placement-points configuration now in effect." }, "TournamentLeaguePointsRejected": { "type": "object", "properties": { "error": { "type": "string", "const": "error_invalid_input" }, "details": { "type": "string" }, "reason": { "description": "Present only when the placement table itself was rejected. Absent for the other 400 causes on this endpoint (a non-league host, or a finalized tournament).", "$ref": "#/components/schemas/TournamentPlacementPointsError" } }, "required": [ "error" ], "additionalProperties": false, "description": "A 400 from this endpoint. A superset of the standard Error body: `reason` adds a machine-readable placement-table reject code when that is what failed." }, "TournamentPlacementPointsError": { "type": "string", "enum": [ "EMPTY", "ALL_ZERO", "TOO_MANY_ROWS", "BAD_PLACEMENT", "BAD_POINTS", "DUPLICATE", "NOT_ASCENDING" ], "description": "Why a placement -> points table was rejected. EMPTY: no rows (omit the field for the default curve, or disable league points). ALL_ZERO: well formed, but no row awards more than 0, so it could never score anything. TOO_MANY_ROWS: more than 32 rows. BAD_PLACEMENT: a placement that is not an integer >= 1. BAD_POINTS: points outside 0-1000. DUPLICATE: the same placement twice. NOT_ASCENDING: placements out of ascending order." }, "MyTournamentEntryResponse": { "type": "object", "properties": { "entry": { "$ref": "#/components/schemas/MyTournamentEntry" }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "entry", "timestamp" ], "additionalProperties": false, "description": "The caller's tournament entry state." }, "MyTournamentEntry": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "Tournament ID." }, "slug": { "type": "string", "description": "The tournament's canonical slug. Echoed because the request may have used a stale one that still resolves." }, "requiredConnectionMissing": { "type": "boolean", "description": "True when the game requires a linked external account the caller has not connected. Surfaced so a client can explain a pre-emptive failure instead of discovering it when the free-agency join is rejected." }, "actableTeams": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentActableTeam" }, "description": "Every team of the tournament's game that the caller may act for - captain, co-captain, or owner of the team's organization. Includes teams NOT yet entered, which is what makes it the enter/apply candidate list." }, "participants": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentParticipant" }, "description": "Every entry belonging to one of the caller's teams, in ALL states including terminal ones. An array, never collapsed to a single row: a caller running several teams in one tournament has several entries and needs every participantId." }, "invites": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentInvite" }, "description": "Every invite addressed to an actable team, in all four states." }, "offers": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentOffer" }, "description": "Every free-agent offer addressed to the caller, in all five states. Filter on `status` for the ones still answerable." }, "rosterEntries": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentRosterEntry" }, "description": "Every tournament roster the caller is personally on. More than one is normal - a player can be rostered for several of their own teams." }, "freeAgent": { "anyOf": [ { "$ref": "#/components/schemas/MyTournamentFreeAgent" }, { "type": "null" } ], "description": "The caller's free-agent row, or null if they have never joined this tournament's pool. A WITHDRAWN row is returned rather than nulled, because the row is reused if they rejoin." } }, "required": [ "tournamentId", "slug", "requiredConnectionMissing", "actableTeams", "participants", "invites", "offers", "rosterEntries", "freeAgent" ], "additionalProperties": false, "description": "The API key owner's own state in one tournament." }, "MyTournamentActableTeam": { "type": "object", "properties": { "teamId": { "type": "string", "description": "Team ID." }, "name": { "type": "string", "description": "Team display name." }, "avatarUrl": { "description": "Team avatar URL.", "type": "string" } }, "required": [ "teamId", "name" ], "additionalProperties": false, "description": "A team the caller may act for in this tournament." }, "MyTournamentParticipant": { "type": "object", "properties": { "participantId": { "type": "string", "description": "Participant ID. Required by the withdraw and check-in endpoints, and by the organizer roster endpoints." }, "teamId": { "type": "string", "description": "Team ID." }, "teamName": { "type": "string", "description": "Team display name." }, "teamAvatarUrl": { "description": "Team avatar URL.", "type": "string" }, "status": { "$ref": "#/components/schemas/TournamentParticipantStatus" }, "seed": { "description": "Assigned seed, once seeding has run.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "checkedInAt": { "description": "Check-in time (epoch milliseconds). Absent until the team checks in.", "type": "number" }, "finalPlacement": { "description": "Placement persisted at finalization. Present only once the tournament ends.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "registeredAt": { "type": "number", "description": "Entry time (epoch milliseconds)." }, "canManage": { "type": "boolean", "description": "Whether the caller may act on this entry - withdraw, check in, or edit its roster. False for a team the caller is an ordinary member of, which still appears here so a client can show it without offering actions that would 403." } }, "required": [ "participantId", "teamId", "teamName", "status", "registeredAt", "canManage" ], "additionalProperties": false, "description": "One of the caller's teams entered in this tournament." }, "TournamentParticipantStatus": { "type": "string", "enum": [ "PENDING", "APPROVED", "DENIED", "WITHDRAWN", "REMOVED", "DISQUALIFIED" ], "description": "State of a team's entry. PENDING is an unreviewed application; REMOVED and DISQUALIFIED are organizer actions, WITHDRAWN is the team's own." }, "MyTournamentInvite": { "type": "object", "properties": { "inviteId": { "type": "string", "description": "Invite ID. Required by the invite-response endpoint." }, "teamId": { "type": "string", "description": "Invited team's ID." }, "teamName": { "type": "string", "description": "Invited team's display name." }, "status": { "$ref": "#/components/schemas/TournamentInviteStatus" }, "invitedByUserId": { "type": "string", "description": "Organizer who sent the invite." }, "createdAt": { "type": "number", "description": "Invite time (epoch milliseconds)." }, "respondedAt": { "description": "Response time (epoch milliseconds). Absent while PENDING.", "type": "number" } }, "required": [ "inviteId", "teamId", "teamName", "status", "invitedByUserId", "createdAt" ], "additionalProperties": false, "description": "An organizer invite addressed to a team the caller may act for. Only invites for ACTABLE teams appear - an invite to a team the caller merely belongs to is the captain's to answer." }, "MyTournamentOffer": { "type": "object", "properties": { "offerId": { "type": "string", "description": "Offer ID. Required by the offer-respond and offer-revoke endpoints." }, "teamId": { "type": "string", "description": "Offering team's ID." }, "teamName": { "type": "string", "description": "Offering team's display name." }, "teamAvatarUrl": { "description": "Offering team's avatar URL.", "type": "string" }, "participantId": { "type": "string", "description": "Offering team's participant ID." }, "offeringParticipantStatus": { "anyOf": [ { "$ref": "#/components/schemas/TournamentParticipantStatus" }, { "type": "null" } ], "description": "The offering team's current entry status, or null if the participant row no longer resolves. Surfaced rather than filtered: the web drops offers whose participant is no longer APPROVED, so they simply vanish. Here a client can tell a dead offer from a live one - accepting a dead one only expires it." }, "status": { "$ref": "#/components/schemas/TournamentFreeAgentOfferStatus" }, "message": { "description": "Optional note from the offering team.", "type": "string" }, "createdAt": { "type": "number", "description": "Offer time (epoch milliseconds)." } }, "required": [ "offerId", "teamId", "teamName", "participantId", "offeringParticipantStatus", "status", "createdAt" ], "additionalProperties": false, "description": "A free-agent offer addressed to the caller, in every state." }, "TournamentFreeAgentOfferStatus": { "type": "string", "enum": [ "PENDING", "ACCEPTED", "DECLINED", "EXPIRED", "REVOKED" ], "description": "State of a free-agent offer. EXPIRED is applied lazily, when the offer is next read or responded to, not by a scheduled sweep." }, "MyTournamentRosterEntry": { "type": "object", "properties": { "rosterEntryId": { "type": "string", "description": "Roster entry ID. Required by the roster-removal endpoints. This is the caller's OWN roster row - a captain removing a different player reads that id from the participants endpoint instead." }, "participantId": { "type": "string", "description": "Participant whose roster the caller is on." }, "source": { "$ref": "#/components/schemas/TournamentRosterSource" }, "addedAt": { "type": "number", "description": "Time the caller was rostered (epoch milliseconds)." } }, "required": [ "rosterEntryId", "participantId", "source", "addedAt" ], "additionalProperties": false, "description": "A tournament roster the caller is personally on." }, "TournamentRosterSource": { "type": "string", "enum": [ "TEAM_MEMBER", "FREE_AGENT" ], "description": "How a player reached a participant's tournament roster." }, "MyTournamentFreeAgent": { "type": "object", "properties": { "freeAgentId": { "type": "string", "description": "Free-agent row ID." }, "status": { "$ref": "#/components/schemas/TournamentFreeAgentStatus" }, "note": { "description": "Free-text note the caller supplied.", "type": "string" }, "pickedUpByParticipantId": { "description": "Participant who picked the caller up. Present only when PICKED_UP.", "type": "string" }, "createdAt": { "type": "number", "description": "Pool join time (epoch milliseconds)." } }, "required": [ "freeAgentId", "status", "createdAt" ], "additionalProperties": false, "description": "The caller's own free-agent pool row." }, "TournamentFreeAgentStatus": { "type": "string", "enum": [ "AVAILABLE", "PICKED_UP", "WITHDRAWN" ], "description": "State of the caller's free-agent pool row." }, "TournamentParticipantsResponse": { "type": "object", "properties": { "participants": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentParticipant" }, "description": "Every participant row for the tournament, in creation order." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of participants returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "participants", "count", "timestamp" ], "additionalProperties": false, "description": "Tournament participants." }, "TournamentParticipant": { "type": "object", "properties": { "id": { "type": "string", "description": "Participant ID." }, "teamId": { "type": "string", "description": "Team ID." }, "teamName": { "type": "string", "description": "Team display name." }, "teamAvatarUrl": { "description": "Team avatar URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "type": "string", "description": "PENDING, APPROVED, DENIED, WITHDRAWN, or DISQUALIFIED." }, "seed": { "description": "Assigned seed, if seeding has run.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "checkedInAt": { "description": "Check-in timestamp (epoch milliseconds).", "type": "number" }, "finalPlacement": { "description": "Placement persisted at finalization. Present only once the tournament ends.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "roster": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentRosterMember" }, "description": "Tournament roster." } }, "required": [ "id", "teamId", "teamName", "status", "roster" ], "additionalProperties": false, "description": "A team entered in a tournament." }, "TournamentRosterMember": { "type": "object", "properties": { "id": { "type": "string", "description": "User ID." }, "username": { "description": "Username.", "type": "string" }, "name": { "description": "Display name.", "type": "string" }, "source": { "type": "string", "description": "How the member joined the tournament roster." }, "avatarUrl": { "description": "Avatar image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "source" ], "additionalProperties": false, "description": "One member of a participant's roster." }, "TournamentRegenerateMatchesResponse": { "type": "object", "properties": { "queued": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "An UPPER BOUND on the nodes this call will re-attempt, NOT a live count of outstanding work. It counts every node that is currently eligible for initial generation at the moment of the call, including nodes a previous sweep already gave up on. Actual generation happens asynchronously afterwards and some of those attempts may fail again, so do not treat `queued` as a number of matches that will exist. `0` means there was nothing eligible to re-attempt and nothing was scheduled." }, "timestamp": { "type": "string" } }, "required": [ "queued", "timestamp" ], "additionalProperties": false, "description": "Acknowledgement that match regeneration was scheduled." }, "TournamentCloseRegistrationResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "status": { "type": "string", "const": "REGISTRATION_CLOSED", "description": "The lifecycle status this call set." }, "timestamp": { "type": "string" } }, "required": [ "success", "status", "timestamp" ], "additionalProperties": false, "description": "Result of closing tournament registration." }, "TournamentOpenRegistrationResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "status": { "type": "string", "const": "REGISTRATION_OPEN", "description": "The lifecycle status this call set." }, "timestamp": { "type": "string" } }, "required": [ "success", "status", "timestamp" ], "additionalProperties": false, "description": "Result of opening tournament registration." }, "TournamentRoundScheduleResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "roundId": { "type": "string" }, "startsAt": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The value now stored on the round." }, "timestamp": { "type": "string" } }, "required": [ "success", "roundId", "startsAt", "timestamp" ], "additionalProperties": false, "description": "Result of scheduling a tournament round." }, "TournamentStaffResponse": { "type": "object", "properties": { "staff": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentStaffMember" }, "description": "Every tournamentStaff row on the tournament. The host is NOT listed here - host authority comes from the host record, not a staff row." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of staff rows returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "staff", "count", "timestamp" ], "additionalProperties": false, "description": "The tournament staff roster." }, "TournamentStaffMember": { "type": "object", "properties": { "id": { "type": "string", "description": "Staff row ID." }, "userId": { "type": "string", "description": "Staff member's user ID." }, "username": { "description": "Username.", "type": "string" }, "name": { "description": "Display name.", "type": "string" }, "avatarUrl": { "description": "Avatar image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "role": { "$ref": "#/components/schemas/TournamentStaffRole" }, "createdAt": { "type": "number", "description": "Time the row was added (epoch milliseconds)." } }, "required": [ "id", "userId", "role", "createdAt" ], "additionalProperties": false, "description": "One tournament staff assignment." }, "TournamentStartResponse": { "type": "object", "properties": { "accepted": { "type": "boolean", "const": true, "description": "The tournament was started and the bracket structure persisted. It does NOT mean matches exist yet." }, "status": { "type": "string", "const": "IN_PROGRESS", "description": "The lifecycle status this call set." }, "nodeCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Size of the generated BRACKET STRUCTURE (nodes), not a count of playable matches and not a count of matches that will be generated. Do not use it as a completion target." }, "matchGeneration": { "type": "string", "const": "pending", "description": "Always `pending`. Match generation runs asynchronously after this response and can partially fail, so there is no success value to report here." }, "timestamp": { "type": "string" } }, "required": [ "accepted", "status", "nodeCount", "matchGeneration", "timestamp" ], "additionalProperties": false, "description": "Acknowledgement that a tournament was started. Matches follow asynchronously." }, "TournamentSubmitForApprovalResponse": { "type": "object", "properties": { "autoApproved": { "type": "boolean", "description": "True when the platform's approval mode skipped review for this tournament. That happens only for an UNLISTED tournament while the mode is `public_listing_only`; the tournament is APPROVED on the spot and no staff review is queued." }, "approvalStatus": { "type": "string", "enum": [ "APPROVED", "AWAITING_APPROVAL" ], "description": "The approval status this call set. APPROVED when `autoApproved` is true, AWAITING_APPROVAL otherwise." }, "timestamp": { "type": "string" } }, "required": [ "autoApproved", "approvalStatus", "timestamp" ], "additionalProperties": false, "description": "Result of submitting a draft tournament for staff review." }, "TournamentTeamEntryResponse": { "type": "object", "properties": { "participantId": { "type": "string", "description": "The team's participant ID. This is the handle the check-in and withdraw endpoints are keyed by, so store it - it is otherwise only rediscoverable through GET /tournaments/{identifier}/me." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "participantId", "timestamp" ], "additionalProperties": false, "description": "The participant row created (or reused) by an entry or application." }, "TournamentUpdateResponse": { "type": "object", "properties": { "applied": { "type": "string", "enum": [ "direct", "pending", "noop" ], "description": "`direct` - the tournament has never been approved, so the edit is live immediately. `pending` - the tournament has been approved before, so the edit was staged in `pendingChanges` and the approval status flipped to AWAITING_APPROVAL; it is NOT live and the tournament is off the public listing until staff re-approve. `noop` - the tournament has been approved before and every supplied value already matched the stored one, so nothing was staged and the approval status was left alone." }, "changedFields": { "description": "Present only when `applied` is `pending`. The material fields staged for re-approval, which is the merge of this request with any changes already pending.", "type": "array", "items": { "$ref": "#/components/schemas/TournamentMaterialField" } }, "approvalStatus": { "description": "Present only when `applied` is `pending`, where it is always AWAITING_APPROVAL. Omitted otherwise, because the `direct` and `noop` arms leave the approval status untouched and echoing a pre-request snapshot would be a guess.", "type": "string", "enum": [ "NOT_SUBMITTED", "AWAITING_APPROVAL", "APPROVED", "REJECTED" ] }, "timestamp": { "type": "string" } }, "required": [ "applied", "timestamp" ], "additionalProperties": false, "description": "Tri-state result of a tournament edit." }, "TournamentMaterialField": { "type": "string", "enum": [ "name", "description", "rules", "gameId", "playlistId", "teamSize", "format", "formatConfig", "minParticipants", "maxParticipants", "registrationMode", "registrationStartsAt", "registrationEndsAt", "checkInRequired", "checkInOpensMinutesBefore", "startsAt", "endsAt", "prizePool", "prizeCurrency", "prizeBreakdown", "prizeDescription", "bannerStorageId", "logoStorageId", "sponsorTags", "socialLinks", "visibility" ], "description": "A tournament field whose edit requires staff re-approval once approved." }, "TournamentDiscoverPage": { "type": "object", "properties": { "tournaments": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentSummary" }, "description": "Tournaments on this page." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of tournaments in this page." }, "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Total tournaments matching the filters." }, "page": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Echo of the requested 1-based page." }, "limit": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Echo of the applied page size." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "tournaments", "count", "total", "page", "limit", "timestamp" ], "additionalProperties": false, "description": "A page of publicly listed tournaments, featured entries first." }, "TournamentSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Tournament ID." }, "name": { "type": "string", "description": "Tournament display name." }, "slug": { "type": "string", "description": "URL-friendly tournament identifier." }, "description": { "description": "Short tournament description.", "type": "string" }, "format": { "$ref": "#/components/schemas/TournamentFormat" }, "status": { "$ref": "#/components/schemas/TournamentStatus" }, "isFeatured": { "type": "boolean", "description": "Whether the featured placement is live at request time." }, "participantCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Current number of participants." }, "maxParticipants": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Participant cap." }, "startsAt": { "description": "Scheduled start (epoch milliseconds).", "type": "number" }, "prizePool": { "description": "Total prize pool.", "type": "number" }, "prizeCurrency": { "description": "ISO currency code of the pool.", "type": "string" }, "bannerUrl": { "description": "Banner image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "logoUrl": { "description": "Logo image URL.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "game": { "anyOf": [ { "type": "object", "properties": {}, "additionalProperties": {} }, { "type": "null" } ], "description": "Game summary, or null if the game row is missing." } }, "required": [ "id", "name", "slug", "format", "status", "isFeatured", "participantCount", "maxParticipants", "game" ], "additionalProperties": false, "description": "Summary view of a tournament for discovery." }, "TwitchChannelBadges": { "type": "object", "properties": { "broadcaster_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Resolved broadcaster (channel) id." }, "broadcaster_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Resolved broadcaster display name or login." }, "badges": { "type": "array", "items": { "$ref": "#/components/schemas/TwitchBadgeSet" }, "description": "Channel-specific Twitch chat badge sets." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "broadcaster_id", "broadcaster_name", "badges", "timestamp" ], "additionalProperties": false, "description": "Channel-specific Twitch chat badges." }, "TwitchBadgeSet": { "type": "object", "properties": { "set_id": { "type": "string", "description": "Badge set identifier (e.g. subscriber, moderator)." }, "versions": { "type": "array", "items": { "$ref": "#/components/schemas/TwitchBadgeVersion" }, "description": "Available versions within this badge set." } }, "required": [ "set_id", "versions" ], "additionalProperties": false, "description": "A set of related Twitch chat badge versions." }, "TwitchBadgeVersion": { "type": "object", "properties": { "id": { "type": "string", "description": "Badge version id (e.g. tier level or numeric id)." }, "image_url_1x": { "type": "string", "description": "Badge image URL at 1x resolution." }, "image_url_2x": { "type": "string", "description": "Badge image URL at 2x resolution." }, "image_url_4x": { "type": "string", "description": "Badge image URL at 4x resolution." }, "title": { "type": "string", "description": "Human-readable badge title." }, "description": { "type": "string", "description": "Human-readable badge description." }, "click_action": { "description": "Optional click action identifier.", "type": "string" }, "click_url": { "description": "Optional URL opened when the badge is clicked.", "type": "string" } }, "required": [ "id", "image_url_1x", "image_url_2x", "image_url_4x", "title", "description" ], "additionalProperties": false, "description": "A single version of a Twitch chat badge." }, "TwitchGlobalBadges": { "type": "object", "properties": { "badges": { "type": "array", "items": { "$ref": "#/components/schemas/TwitchBadgeSet" }, "description": "Global Twitch chat badge sets." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "badges", "timestamp" ], "additionalProperties": false, "description": "Global Twitch chat badges." }, "ImageUploadUrlResponse": { "type": "object", "properties": { "uploadUrl": { "type": "string", "description": "Short-lived, single-use URL to POST the image bytes to." } }, "required": [ "uploadUrl" ], "additionalProperties": false, "description": "A freshly minted Convex storage upload URL. POST the image to it to receive a storageId for use on a downstream write." }, "ApiOwnConnection": { "type": "object", "properties": { "id": { "type": "string", "description": "Connection ID." }, "platform": { "type": "string", "description": "Connected platform." }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isPrimary": { "type": "boolean" }, "isVerified": { "type": "boolean" }, "connectedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] }, "isSelfReported": { "type": "boolean", "description": "True when the connection was self-reported (ownership unverified)." }, "showOnProfile": { "type": "boolean", "description": "Whether the owner has chosen to show this connection on their profile." }, "region": { "description": "Connection region, when set.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "gamingPlatform": { "description": "Gaming platform (e.g. pc / console), when set.", "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "platform", "isSelfReported", "showOnProfile" ], "additionalProperties": false, "description": "API-safe connection for the API key owner, including private fields." }, "GameRankListResponse": { "type": "object", "properties": { "gameRanks": { "type": "array", "items": { "$ref": "#/components/schemas/ApiGameRank" } }, "count": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "timestamp": { "type": "string", "description": "ISO 8601 response timestamp." } }, "required": [ "gameRanks", "count", "timestamp" ], "additionalProperties": false, "description": "The API key owner's game ranks." }, "ApiGameRank": { "type": "object", "properties": { "id": { "type": "string", "description": "Game rank row ID." }, "gameId": { "type": "string", "description": "Game definition ID this rank belongs to." }, "mode": { "type": "string", "description": "Game mode / playlist the rank is tracked for." }, "source": { "type": "string", "enum": [ "manual", "api" ], "description": "Origin of the rank: manual entry or an API push." }, "sr": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Skill rating, when set." }, "isTop250": { "type": "boolean", "description": "Whether the player is in the Top 250 ladder." }, "top250Rank": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "Top 250 ladder position (1-250), when applicable." }, "winstreak": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Current win streak count." }, "updatedAt": { "type": "string", "description": "When the rank was last updated." }, "createdAt": { "type": "string", "description": "When the rank was first recorded." } }, "required": [ "id", "gameId", "mode", "source", "sr", "isTop250", "top250Rank", "winstreak", "updatedAt", "createdAt" ], "additionalProperties": false, "description": "API-safe game rank entry for the API key owner." }, "GameRankUpsertResponse": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the upserted game rank row." }, "timestamp": { "type": "string", "description": "ISO 8601 response timestamp." } }, "required": [ "id", "timestamp" ], "additionalProperties": false, "description": "Result of upserting a game rank." }, "GameRankDeleteResponse": { "type": "object", "properties": { "deleted": { "type": "boolean", "description": "True when a rank was removed; false when none existed (no-op)." }, "timestamp": { "type": "string", "description": "ISO 8601 response timestamp." } }, "required": [ "deleted", "timestamp" ], "additionalProperties": false, "description": "Result of deleting a game rank." }, "OngoingMatchesResponse": { "type": "object", "properties": { "matches": { "type": "array", "items": { "$ref": "#/components/schemas/ApiMatchDetail" } }, "timestamp": { "type": "string" } }, "required": [ "matches", "timestamp" ], "additionalProperties": false, "description": "Ongoing matches for the API key owner's active teams." }, "MyTournamentsResponse": { "type": "object", "properties": { "tournaments": { "type": "array", "items": { "$ref": "#/components/schemas/MyTournamentSummary" }, "description": "Tournaments the caller manages, including drafts and unapproved ones. Capped at 100." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of tournaments returned." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "tournaments", "count", "timestamp" ], "additionalProperties": false, "description": "The key owner's manageable tournaments." }, "MyTournamentSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Tournament ID." }, "name": { "type": "string", "description": "Tournament display name." }, "slug": { "type": "string", "description": "URL-friendly tournament identifier." }, "status": { "$ref": "#/components/schemas/TournamentStatus" }, "approvalStatus": { "type": "string", "description": "Platform review state, independent of `status`." }, "needsAttention": { "type": "boolean", "description": "Non-terminal AND awaiting organizer action on approval. Tournaments sort attention-first, then by most recently updated." }, "hostType": { "type": "string", "description": "user, org, or league." }, "participantCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Current number of participants." }, "maxParticipants": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Participant cap." }, "startsAt": { "description": "Scheduled start (epoch milliseconds).", "type": "number" }, "updatedAt": { "type": "number", "description": "Last update (epoch milliseconds)." }, "isAdmin": { "type": "boolean", "description": "Whether the caller holds tournament ADMIN authority. False for a tournament moderator, who is a manager but not an admin." } }, "required": [ "id", "name", "slug", "status", "approvalStatus", "needsAttention", "hostType", "participantCount", "maxParticipants", "updatedAt", "isAdmin" ], "additionalProperties": false, "description": "A tournament the API key owner can manage." }, "TournamentCalendarResponse": { "type": "object", "properties": { "events": { "type": "array", "items": { "$ref": "#/components/schemas/TournamentCalendarEvent" }, "description": "Milestones in the requested window, ascending by time." }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of milestones returned." }, "rangeStart": { "type": "string", "description": "Applied window start (ISO 8601)." }, "rangeEnd": { "type": "string", "description": "Applied window end (ISO 8601)." }, "timestamp": { "type": "string", "description": "Response generation time (ISO 8601)." } }, "required": [ "events", "count", "rangeStart", "rangeEnd", "timestamp" ], "additionalProperties": false, "description": "Tournament milestones for the key owner's teams." }, "TournamentCalendarEvent": { "type": "object", "properties": { "tournamentId": { "type": "string", "description": "Tournament ID." }, "slug": { "type": "string", "description": "URL-friendly tournament identifier." }, "name": { "type": "string", "description": "Tournament display name." }, "kind": { "type": "string", "enum": [ "registration", "checkin", "start" ], "description": "registration = registration deadline, checkin = check-in opens, start = tournament start." }, "at": { "type": "number", "description": "Milestone time (epoch milliseconds)." } }, "required": [ "tournamentId", "slug", "name", "kind", "at" ], "additionalProperties": false, "description": "One dated tournament milestone for the key owner." }, "ApiUserConnection": { "type": "object", "properties": { "id": { "type": "string", "description": "Connection ID." }, "platform": { "type": "string", "description": "Connected platform." }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isPrimary": { "type": "boolean" }, "isVerified": { "type": "boolean" }, "connectedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "platform" ], "additionalProperties": false, "description": "API-safe public account connection." }, "ApiUserOrganizationMembership": { "type": "object", "properties": { "id": { "type": "string", "description": "Organization ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Organization name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" }, "role": { "type": "string" }, "joinedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "name", "role", "joinedAt" ], "additionalProperties": false, "description": "API-safe organization affiliation row on a user profile." }, "ApiUserStats": { "type": "object", "properties": { "userId": { "type": "string", "description": "User ID these stats belong to." }, "matchesPlayed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "wins": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "losses": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "draws": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "winRate": { "type": "number", "minimum": 0, "maximum": 1 }, "experience": { "type": "number", "minimum": 0 }, "currentStreak": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "bestStreak": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "userId", "matchesPlayed", "wins", "losses", "winRate", "experience" ], "additionalProperties": false, "description": "API-safe aggregate user stats." }, "ApiStreamStatusEnvelope": { "type": "object", "properties": { "stream": { "$ref": "#/components/schemas/ApiStreamStatus" }, "timestamp": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "stream", "timestamp" ], "additionalProperties": false, "description": "Stream status plus a response timestamp." }, "ApiStreamStatus": { "type": "object", "properties": { "userId": { "type": "string", "description": "User ID these stream details belong to." }, "isLive": { "type": "boolean", "description": "Whether the user is live on any platform." }, "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/StreamPlatform" }, "description": "Platforms the user is currently live on." }, "primaryStream": { "anyOf": [ { "$ref": "#/components/schemas/ApiPrimaryStream" }, { "type": "null" } ], "description": "Primary stream details, or null when offline." } }, "required": [ "userId", "isLive", "platforms", "primaryStream" ], "additionalProperties": false, "description": "API-safe live-stream status for a user." }, "ApiPrimaryStream": { "type": "object", "properties": { "platform": { "$ref": "#/components/schemas/StreamPlatform" }, "streamUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Watch URL, when known." }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Stream title, when known." }, "gameName": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Game/category being streamed, when known." }, "viewerCount": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "Current viewer count, when known." }, "thumbnailUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Stream thumbnail URL, when known." }, "startedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Stream start time (platform-provided ISO timestamp), when known." }, "lastLiveAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO timestamp the user was last observed live, when known." } }, "required": [ "platform", "streamUrl", "title", "gameName", "viewerCount", "thumbnailUrl", "startedAt", "lastLiveAt" ], "additionalProperties": false, "description": "The user's primary (highest-viewer) live stream." }, "ApiUserTeamMembership": { "type": "object", "properties": { "id": { "type": "string", "description": "Team ID." }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string", "description": "Team name." }, "tag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatarUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "$ref": "#/components/schemas/ProfileVisibility" }, "role": { "type": "string" }, "joinedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] }, "organization": { "anyOf": [ { "$ref": "#/components/schemas/ApiOrganizationSummary" }, { "type": "null" } ] } }, "required": [ "id", "name", "role", "joinedAt" ], "additionalProperties": false, "description": "API-safe team affiliation row on a user profile." }, "ApiUserTrophy": { "type": "object", "properties": { "id": { "type": "string", "description": "Trophy award ID." }, "trophyId": { "type": "string", "description": "Trophy definition ID." }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "iconUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rarity": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "awardedAt": { "anyOf": [ { "type": "string", "description": "ISO 8601 timestamp." }, { "type": "null" } ] } }, "required": [ "id", "trophyId", "awardedAt" ], "additionalProperties": false, "description": "API-safe user trophy. Event linkage fields are intentionally omitted." }, "WebhookListResponse": { "type": "object", "properties": { "webhooks": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEndpoint" } }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "timestamp": { "type": "string" } }, "required": [ "webhooks", "count", "timestamp" ], "additionalProperties": false, "description": "List of the caller's webhook endpoints." }, "WebhookEndpoint": { "type": "object", "properties": { "id": { "type": "string", "description": "Webhook endpoint id." }, "scopeType": { "type": "string", "enum": [ "game", "league", "org", "team", "user" ], "description": "The single scope dimension an endpoint is bound to." }, "scopeId": { "type": "string", "description": "Stringified bound scope id." }, "url": { "type": "string", "description": "Delivery URL." }, "secretPrefix": { "type": "string", "description": "First 8 chars of the current signing secret (display only)." }, "events": { "type": "array", "items": { "type": "string" }, "description": "Subscribed event tokens." }, "isActive": { "type": "boolean", "description": "Whether the endpoint receives deliveries." }, "label": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Human label, or null." }, "failureCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Consecutive dead-lettered deliveries (auto-disables at 50)." }, "lastDeliveredAt": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Epoch ms of the last successful delivery, or null." }, "lastFailedAt": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Epoch ms of the last failed delivery, or null." }, "createdAt": { "type": "number", "description": "Creation epoch ms." }, "updatedAt": { "type": "number", "description": "Last update epoch ms." } }, "required": [ "id", "scopeType", "scopeId", "url", "secretPrefix", "events", "isActive", "label", "failureCount", "lastDeliveredAt", "lastFailedAt", "createdAt", "updatedAt" ], "additionalProperties": false, "description": "A webhook endpoint (no secret material)." }, "WebhookSecret": { "type": "object", "properties": { "id": { "type": "string", "description": "The endpoint id the secret belongs to." }, "signingSecret": { "type": "string", "description": "Plaintext signing secret. Shown ONCE - store it now." }, "secretPrefix": { "type": "string", "description": "First 8 chars of the new signing secret." } }, "required": [ "id", "signingSecret", "secretPrefix" ], "additionalProperties": false, "description": "One-time signing-secret reveal (create/rotate)." }, "WebhookOk": { "type": "object", "properties": { "ok": { "type": "boolean" } }, "required": [ "ok" ], "additionalProperties": false, "description": "Success ack." }, "WebhookDelivery": { "type": "object", "properties": { "id": { "type": "string", "description": "Delivery-log row id." }, "idempotencyId": { "type": "string", "description": "Stable evt_ id, reused across retries (idempotency key)." }, "event": { "type": "string", "description": "The delivered event name." }, "status": { "type": "string", "enum": [ "pending", "delivering", "delivered", "failed", "dead_lettered" ], "description": "Lifecycle status of one logical delivery (endpoint x idempotency id)." }, "attemptCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of delivery attempts made." }, "statusCode": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "Last HTTP response status, or null." }, "errorMessage": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Last error message, or null." }, "nextAttemptAt": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Epoch ms of the next scheduled retry, or null." }, "isTest": { "type": "boolean", "description": "True for test.ping deliveries." }, "createdAt": { "type": "number", "description": "Emit/creation epoch ms (retention key)." }, "updatedAt": { "type": "number", "description": "Last update epoch ms." }, "deliveredAt": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Epoch ms of successful delivery, or null." } }, "required": [ "id", "idempotencyId", "event", "status", "attemptCount", "statusCode", "errorMessage", "nextAttemptAt", "isTest", "createdAt", "updatedAt", "deliveredAt" ], "additionalProperties": false, "description": "A single webhook delivery-log row." }, "WebhookReplayResult": { "type": "object", "properties": { "ok": { "type": "boolean" } }, "required": [ "ok" ], "additionalProperties": false, "description": "Replay re-queue acknowledgement." }, "WebhookTestResult": { "type": "object", "properties": { "delivered": { "type": "boolean", "description": "Whether the test.ping returned a 2xx. The raw status code and error are not echoed; read the delivery log for details." } }, "required": [ "delivered" ], "additionalProperties": false, "description": "Outcome of a single test.ping delivery." }, "ApiErrorCode": { "type": "string", "enum": [ "error_api_key_invalid", "error_api_key_expired", "error_api_key_muted", "error_api_rate_limited", "error_ip_rate_limited", "error_api_key_permission_denied", "error_api_key_required", "error_api_plan_required", "error_api_feature_required", "error_developer_account_required", "error_game_scope_mismatch", "error_league_scope_mismatch", "error_unauthorized", "error_user_banned", "error_invalid_input", "error_invalid_request", "error_invalid_limit", "error_invalid_cursor", "error_invalid_date_format", "error_invalid_best_of", "error_invalid_score_value", "error_invalid_game_rank", "error_forbidden", "error_user_not_found", "error_team_not_found", "error_org_not_found", "error_match_not_found", "error_game_not_found", "error_league_not_found", "error_league_game_not_found", "error_league_game_not_active", "error_league_season_not_found", "error_league_admin_required", "error_league_team_not_in_league", "error_not_match_participant", "error_not_team_leader", "error_tournament_not_found", "error_not_tournament_staff", "error_not_eligible_to_host", "error_approval_required", "error_approval_pending", "error_tournament_full", "error_revert_blocked_downstream", "error_registration_closed", "error_roster_too_small", "error_already_entered", "error_competitive_banned", "error_check_in_closed", "error_free_agent_account_required", "error_free_agent_already_in_pool", "error_free_agent_offer_exists", "error_free_agent_offer_not_pending", "error_not_org_admin", "error_internal", "error_webhook_not_found", "error_webhook_url_invalid", "error_webhook_limit_reached", "error_webhook_invalid_events", "error_webhook_delivery_not_found", "error_webhook_replay_not_allowed", "error_webhook_scope_invalid", "error_idempotency_key_conflict", "error_team_name_taken", "error_team_tag_taken", "error_team_not_active", "error_team_game_mismatch", "error_team_not_in_match", "error_only_team_leaders_can_add_members", "error_only_team_leaders_can_remove_members", "error_cannot_remove_captain", "error_captain_must_transfer_before_leave", "error_captain_role_requires_transfer", "error_captain_cannot_change_own_role", "error_captain_required", "error_not_team_member", "error_already_team_member", "error_no_permission_disable_team", "error_no_permission_enable_team", "error_cannot_enable_team_org_disabled", "error_no_permission_invite_members", "error_must_be_org_member_to_join_team", "error_only_org_admins_can_add_members", "error_only_org_admins_can_remove_members", "error_only_org_admins_can_create_teams", "error_cannot_remove_org_owner", "error_only_org_owner_can_change_roles", "error_cannot_change_owner_role", "error_only_org_owner_can_transfer", "error_new_owner_must_be_member", "error_only_org_owner_can_delete", "error_only_org_owner_can_disable", "error_only_org_owner_can_enable", "error_not_org_member", "error_already_org_member", "error_must_leave_teams_first", "error_org_already_disabled", "error_org_not_disabled", "error_match_already_published", "error_match_not_published", "error_match_already_accepted", "error_match_already_started", "error_match_not_accepted", "error_match_not_ready", "error_match_no_accepted_team", "error_match_has_acceptances", "error_match_cannot_accept_own", "error_match_not_challenge", "error_challenge_not_pending", "error_challenge_already_pending", "error_challenge_game_mismatch", "error_cannot_challenge_self", "error_challenged_team_not_found", "error_max_open_challenges_reached", "error_only_captains_can_start_match", "error_only_captains_can_respond_challenge", "error_only_captains_can_pass_host", "error_only_host_can_pass_host", "error_only_captains_can_update_lobby", "error_acceptance_not_found", "error_acceptance_not_pending", "error_acceptance_already_pending", "error_acceptance_rejected", "error_lobby_code_required", "error_lobby_code_too_long", "error_lobby_code_invalid_status", "error_invalid_game_mode", "error_invalid_map_selection", "error_invalid_map_selection_type", "error_invalid_game_specific_option", "error_map_not_released", "error_map_selection_not_supported", "error_validation_failed" ], "description": "Stable machine-readable API error code (documentation enum)." }, "WebhookEnvelope": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable delivery id, reused across retries (idempotency key)." }, "event": { "type": "string", "enum": [ "match.accepted", "match.cancelled", "match.completed", "match.created", "match.forfeited", "match.published", "match.ready", "match.started", "score.confirmed", "score.dispute_resolved", "score.disputed", "score.submitted", "roster.updated", "player.checked_in", "player.stats_updated", "team.banned", "team.created", "team.disbanded", "team.joined", "team.left", "team.member_role_changed", "team.updated", "organization.created", "organization.disabled", "organization.enabled", "organization.member_added", "organization.member_removed", "organization.member_role_changed", "organization.ownership_transferred", "organization.removed", "organization.unbanned", "organization.updated", "organization.user_banned", "league.announcement", "league.ban_revoked", "league.cooldown_cleared", "league.cooldown_issued", "league.created", "league.display_rules_updated", "league.featured", "league.game_added", "league.game_removed", "league.game_toggled", "league.ownership_transferred", "league.penalty_issued", "league.points_updated", "league.rules_updated", "league.season_activated", "league.season_completed", "league.season_created", "league.season_removed", "league.settings_updated", "league.shutdown", "league.shutdown_requested", "league.staff_invited", "league.staff_removed", "league.staff_role_changed", "league.standings_updated", "league.suspended", "league.team_approved", "league.team_banned", "league.team_denied", "league.team_removed", "league.unfeatured", "league.unsuspended", "league.verified", "rank.updated", "stream.offline", "stream.online", "subscription.cancelled", "subscription.created", "subscription.updated", "payment.failed", "payment.refunded", "payment.succeeded", "ticket.closed", "ticket.created", "ticket.reopened", "ticket.updated", "chat.message_reported", "custommap.scan_completed", "achievement.unlocked", "referral.milestone", "trophy.awarded", "tournament.approved", "tournament.registration_opened", "tournament.participant_approved", "tournament.started", "tournament.round_completed", "tournament.completed", "tournament.cancelled", "tournament.featured", "tournament.unfeatured" ], "description": "The event name from the TeamBattles catalog." }, "created_at": { "type": "string", "description": "ISO-8601 timestamp the event was emitted." }, "data": { "type": "object", "properties": {}, "additionalProperties": {}, "description": "Event-specific payload." } }, "required": [ "id", "event", "created_at", "data" ], "additionalProperties": false, "description": "Shared envelope for all TeamBattles webhook deliveries." } }, "securitySchemes": { "ApiKeyAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "API Key", "description": "Send your API key as: Authorization: Bearer tb_" } } } }