{"openapi":"3.0.3","info":{"title":"Pulse API","version":"0.1.0","description":"Live results, score tracking, and leaderboards for E-Arena tournaments. Read endpoints under /api/v1 require a bearer token; /webhooks/results accepts signed result updates from registered sources."},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Static API token (PULSE_API_TOKEN) required for /api/v1 routes"}},"schemas":{}},"paths":{"/health":{"get":{"summary":"Liveness check","tags":["Health"],"description":"Returns ok if the service is running. Does not check database connectivity.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"],"additionalProperties":false}}}}}}},"/health/ready":{"get":{"summary":"Readiness check","tags":["Health"],"description":"Returns ok if the service can reach the database. Use as a readiness probe.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"],"additionalProperties":false}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"],"additionalProperties":false}}}}}}},"/webhooks/results":{"post":{"summary":"Ingest a signed match result update","tags":["Webhooks"],"description":"Accepts result updates from registered webhook sources. Requires the headers X-Pulse-Source (name of a row in webhook_sources), X-Pulse-Timestamp (unix seconds, within 5 minutes of server time), and X-Pulse-Signature (sha256=<hmac-sha256 of \"${timestamp}.${rawBody}\" using the source secret>). The request body must match the webhook envelope shape, with `gameType` matching a registered game adapter and `result` matching that game's result schema.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"matchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["success","matchId"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/webhooks/facts":{"post":{"summary":"Ingest per-team FACTS rows for an already-ingested match","tags":["Webhooks"],"description":"Accepts derived FACTS analysis rows from registered webhook sources, signed the same way as /webhooks/results. The match must already exist in Pulse (posted via /webhooks/results); each row upserts on (match, teamKey), where teamKey follows the same rule as the stats endpoints (participant's sanityTeamId, else externalKey, else displayName).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"matchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["success","matchId","rows"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/webhooks/facts/pending":{"post":{"summary":"List tournament matches still missing FACTS rows","tags":["Webhooks"],"description":"Read-only, but authenticated exactly like the other /webhooks/* routes (signed source, not the bearer token used by /api/v1) because the response carries player account ids. Lists tournament matches of `gameType` (tournamentId set, status completed, not voided, a recorded startedAt) that have zero rows in team_match_facts yet, so pubg-ingest can compute their FACTS rows from stored telemetry without another PUBG API call. A match with no startedAt is never listed. Ordered by startedAt descending, then id; page with `before` (exclusive) using the previous page's `nextBefore`, which is null once the last page is short. `teams[].accountIds` is each participant's distinct, non-empty result.players[].accountId values, in first-seen order; a participant with none is still listed, with an empty array. Optional `minVersion` also lists a match whose FACTS rows are all below that version, so a FACTS_VERSION bump can get older matches recomputed too.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"matches":{"type":"array","items":{"type":"object","properties":{"externalMatchId":{"type":"string"},"startedAt":{"type":"string"},"teams":{"type":"array","items":{"type":"object","properties":{"teamKey":{"type":"string"},"accountIds":{"type":"array","items":{"type":"string"}}},"required":["teamKey","accountIds"],"additionalProperties":false}}},"required":["externalMatchId","startedAt","teams"],"additionalProperties":false}},"nextBefore":{"nullable":true,"type":"string"}},"required":["matches","nextBefore"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/live/sessions":{"post":{"summary":"Bind a certified operator to a live scoreboard session","tags":["Live"],"description":"Creates (or resumes) a live scoreboard session for a tournament-structure match. Requires the same signed headers as /webhooks/results, signed by a certified-operator source authorized for the game. Returns the sessionId the OCR agent posts snapshots against.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"resumed":{"type":"boolean"},"session":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"type":"string"},"roundId":{"nullable":true,"type":"string"},"structureMatchId":{"type":"string"},"gameNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxGames":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","ended"]},"lastSequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updatedAt":{"type":"string"}},"required":["sessionId","tournamentSanityId","bracketId","divisionId","roundId","structureMatchId","gameNumber","maxGames","status","lastSequence","updatedAt"],"additionalProperties":false}},"required":["success","resumed","session"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/live/state":{"post":{"summary":"Ingest a folded provisional snapshot","tags":["Live"],"description":"Accepts one live-match-state-v1 snapshot (folded, applied, provisional only — never raw OCR or review-layer events). Signed like /live/sessions. The snapshot routing key (sessionId + structureMatchId + gameNumber) must match the bound session; sequence must be monotonic (stale sequences are acknowledged but ignored).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"sequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stale":{"type":"boolean"}},"required":["success","sequence","stale"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}":{"put":{"summary":"Upsert a tournament by Sanity id (idempotent)","tags":["Tournaments"],"description":"Ensures the tournament row exists in Pulse (creating the game by slug if needed) so structure and registration writes can proceed. Called by sanity-web on publish/registration. `scoringRules` carries the scoring profile — what a win, draw and loss are worth and the order tiebreakers are applied in. Omit it to leave the stored profile alone; send null to clear it and fall back to the defaults (3/1/0, points → goal difference → goals for → head-to-head).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"gameSlug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"scoringRules":{"nullable":true,"type":"object","properties":{"model":{"type":"string","enum":["football-v1"]},"points":{"type":"object","properties":{"win":{"type":"integer","minimum":-99,"maximum":99},"draw":{"type":"integer","minimum":-99,"maximum":99},"loss":{"type":"integer","minimum":-99,"maximum":99}},"required":["win","draw","loss"],"additionalProperties":false},"tiebreakers":{"minItems":1,"maxItems":4,"type":"array","items":{"type":"string","enum":["points","goalDiff","goalsFor","headToHead"]}},"ratingWeight":{"type":"number","minimum":0,"maximum":5}},"required":["model","points","tiebreakers"],"additionalProperties":false}},"required":["gameSlug","name"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false}},"required":["tournament"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Delete a tournament and everything belonging to it","tags":["Tournaments"],"description":"Removes the tournament, its matches and every dependent row. Irreversible — results are not recoverable afterwards. `confirmName` must equal the tournament name, and `force` is required when the tournament has matches. Structure authored in Sanity is untouched, so republishing rebuilds the tournament from scratch; this is also how a rehearsal is reset.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmName":{"type":"string","minLength":1,"description":"Must equal the tournament name"},"force":{"default":false,"description":"Required when the tournament has matches","type":"boolean"},"actorName":{"description":"Recorded on the audit row","type":"string","minLength":1}},"required":["confirmName"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"object","properties":{"matches":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"matchPins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"liveSessions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slotReservations":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAdjustments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["matches","matchPins","liveSessions","slotReservations","scoreAdjustments"],"additionalProperties":false}},"required":["deleted"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}},"matchCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["error","matchCount"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/matches":{"get":{"summary":"List matches for a tournament","tags":["Tournaments"],"description":"Returns the tournament and all of its matches (each with their participants), ordered by start time, then by ingestion time for matches whose source reported no start time.","parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed"]},"voided":{"type":"boolean"},"provenance":{"type":"string","enum":["ingest","manual"]},"startedAt":{"nullable":true,"type":"string","format":"date-time"},"endedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"participants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityPersonId":{"nullable":true,"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"result":{"nullable":true},"score":{"nullable":true,"type":"number"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","matchId","sanityPersonId","sanityTeamId","displayName","result","score","createdAt"],"additionalProperties":false}}},"required":["id","tournamentId","gameId","externalId","bracketId","divisionId","roundId","status","voided","provenance","startedAt","endedAt","createdAt","updatedAt","participants"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["tournament","matches","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/matches/{id}":{"get":{"summary":"Get a match by id","tags":["Matches"],"description":"Returns a single match along with its participants.","parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed"]},"voided":{"type":"boolean"},"provenance":{"type":"string","enum":["ingest","manual"]},"startedAt":{"nullable":true,"type":"string","format":"date-time"},"endedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"participants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityPersonId":{"nullable":true,"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"result":{"nullable":true},"score":{"nullable":true,"type":"number"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","matchId","sanityPersonId","sanityTeamId","displayName","result","score","createdAt"],"additionalProperties":false}}},"required":["id","tournamentId","gameId","externalId","bracketId","divisionId","roundId","status","voided","provenance","startedAt","endedAt","createdAt","updatedAt","participants"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/matches/{externalId}/void":{"post":{"summary":"Void or restore a match (operator override)","tags":["Matches"],"description":"Marks a match voided (excluded from standings, kept for audit) or restores it. Sets provenance=manual so automatic ingest will not overwrite the decision on a later poll.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voided":{"default":true,"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true},{"schema":{"type":"string","minLength":1},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed"]},"voided":{"type":"boolean"},"provenance":{"type":"string","enum":["ingest","manual"]},"startedAt":{"nullable":true,"type":"string","format":"date-time"},"endedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"participants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityPersonId":{"nullable":true,"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"result":{"nullable":true},"score":{"nullable":true,"type":"number"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","matchId","sanityPersonId","sanityTeamId","displayName","result","score","createdAt"],"additionalProperties":false}}},"required":["id","tournamentId","gameId","externalId","bracketId","divisionId","roundId","status","voided","provenance","startedAt","endedAt","createdAt","updatedAt","participants"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/match-pins":{"get":{"summary":"List operator-pinned match ids for a tournament","tags":["Matches"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pins":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"externalMatchId":{"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"reason":{"nullable":true,"type":"string"},"createdByPersonId":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","tournamentSanityId","externalMatchId","divisionId","roundId","reason","createdByPersonId","createdAt"],"additionalProperties":false}}},"required":["pins"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Pin a match id (operator override — worker will fetch + post it as manual)","tags":["Matches"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalMatchId":{"type":"string","minLength":1},"divisionId":{"type":"string","minLength":1},"roundId":{"type":"string","minLength":1},"reason":{"type":"string","maxLength":2000},"createdByPersonId":{"type":"string"}},"required":["externalMatchId"]}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pin":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"externalMatchId":{"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"reason":{"nullable":true,"type":"string"},"createdByPersonId":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","tournamentSanityId","externalMatchId","divisionId","roundId","reason","createdByPersonId","createdAt"],"additionalProperties":false}},"required":["pin"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/match-pins/{externalMatchId}":{"delete":{"summary":"Remove a match pin","tags":["Matches"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true},{"schema":{"type":"string"},"in":"path","name":"externalMatchId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"}},"required":["removed"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/leaderboard":{"get":{"summary":"Get the leaderboard for a tournament","tags":["Tournaments"],"description":"Returns aggregated standings (total score and matches played) per participant, ordered by total score descending. Optionally narrowed to a structureTree scope via bracketId / divisionId / roundId query params. PUBG boards break a points tie by the official SUPER §10.5 chain — accumulated placement points, then match points, survival ranking and damage in the scope’s last match — and carry those inputs on each row so a caller that re-ranks the board settles its ties the same way.","parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"standings":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"totalScore":{"nullable":true,"type":"number"},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kills":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"placementPoints":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"damage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastMatchPoints":{"type":"number"},"lastMatchPlacement":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastMatchDamage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["key","displayName","totalScore","matchesPlayed"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["tournament","standings","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/ladder":{"get":{"summary":"Get the individual Battle Royale Ladder standings for a tournament","tags":["Tournaments"],"description":"Full-parity ladder read for the PUBG individual ladder: one row per player ranked by their best-N match scores, each with the counted matches and per-match breakdown for the player detail view. Best-N comes from the tournament scoring config (defaults to 5). Optionally narrowed to a structureTree scope via bracketId / divisionId / roundId.","parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"standings":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"number"},"key":{"type":"string"},"sanityPersonId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"totalScore":{"type":"number"},"bestScore":{"type":"number"},"gamesPlayed":{"type":"number"},"topMatches":{"type":"array","items":{"type":"object","properties":{"externalMatchId":{"nullable":true,"type":"string"},"map":{"nullable":true,"type":"string"},"playedAt":{"nullable":true,"type":"string"},"score":{"type":"number"},"placement":{"nullable":true,"type":"number"},"kills":{"nullable":true,"type":"number"},"assists":{"nullable":true,"type":"number"},"damage":{"nullable":true,"type":"number"},"survivalTime":{"nullable":true,"type":"number"},"breakdown":{"nullable":true,"type":"object","additionalProperties":{"type":"number"}}},"required":["externalMatchId","map","playedAt","score","placement","kills","assists","damage","survivalTime","breakdown"],"additionalProperties":false}}},"required":["rank","key","sanityPersonId","displayName","totalScore","bestScore","gamesPlayed","topMatches"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["tournament","standings","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/stats":{"get":{"summary":"Per-player and per-team statistics for a tournament","tags":["Tournaments"],"description":"Sums the per-match participant results (and their result.players breakdown) into one row per player and one per team, with single-match records, over the completed, unvoided matches of a structureTree scope (bracketId / divisionId / roundId) or of one match of that scope (matchId = the source match id). Extended stats are null until a counted match carried them.","parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"matchId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"externalId":{"type":"string"},"startedAt":{"nullable":true,"type":"string"},"map":{"nullable":true,"type":"string"}},"required":["externalId","startedAt","map"],"additionalProperties":false}},"counted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"players":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"accountId":{"nullable":true,"type":"string"},"teamKey":{"type":"string"},"teamName":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"matches":{"type":"number"},"wins":{"type":"number"},"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"extrasMatches":{"type":"number"},"headshotKills":{"nullable":true,"type":"number"},"revives":{"nullable":true,"type":"number"},"heals":{"nullable":true,"type":"number"},"boosts":{"nullable":true,"type":"number"},"weaponsAcquired":{"nullable":true,"type":"number"},"walkDistance":{"nullable":true,"type":"number"},"rideDistance":{"nullable":true,"type":"number"},"swimDistance":{"nullable":true,"type":"number"},"vehicleDestroys":{"nullable":true,"type":"number"},"roadKills":{"nullable":true,"type":"number"},"teamKills":{"nullable":true,"type":"number"},"longestKill":{"nullable":true,"type":"number"},"killStreaks":{"nullable":true,"type":"number"},"deaths":{"nullable":true,"type":"number"},"deathsByZone":{"nullable":true,"type":"number"},"suicides":{"nullable":true,"type":"number"},"earliestDeath":{"nullable":true,"type":"number"},"best":{"type":"object","properties":{"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"revives":{"nullable":true,"type":"number"},"headshotKills":{"nullable":true,"type":"number"}},"required":["kills","assists","damage","dbnos","survivalTime","revives","headshotKills"],"additionalProperties":false}},"required":["key","name","accountId","teamKey","teamName","sanityTeamId","matches","wins","kills","assists","damage","dbnos","survivalTime","extrasMatches","headshotKills","revives","heals","boosts","weaponsAcquired","walkDistance","rideDistance","swimDistance","vehicleDestroys","roadKills","teamKills","longestKill","killStreaks","deaths","deathsByZone","suicides","earliestDeath","best"],"additionalProperties":false}},"teams":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"matches":{"type":"number"},"wins":{"type":"number"},"top4":{"type":"number"},"top8":{"type":"number"},"avgPlacement":{"nullable":true,"type":"number"},"points":{"type":"number"},"placementPoints":{"type":"number"},"killPoints":{"type":"number"},"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"extrasMatches":{"type":"number"},"headshotKills":{"nullable":true,"type":"number"},"revives":{"nullable":true,"type":"number"},"heals":{"nullable":true,"type":"number"},"boosts":{"nullable":true,"type":"number"},"vehicleDestroys":{"nullable":true,"type":"number"},"roadKills":{"nullable":true,"type":"number"},"teamKills":{"nullable":true,"type":"number"},"walkDistance":{"nullable":true,"type":"number"},"rideDistance":{"nullable":true,"type":"number"},"swimDistance":{"nullable":true,"type":"number"},"longestKill":{"nullable":true,"type":"number"},"deaths":{"nullable":true,"type":"number"},"best":{"type":"object","properties":{"kills":{"type":"number"},"damage":{"type":"number"},"points":{"type":"number"},"placement":{"nullable":true,"type":"number"}},"required":["kills","damage","points","placement"],"additionalProperties":false}},"required":["key","name","sanityTeamId","matches","wins","top4","top8","avgPlacement","points","placementPoints","killPoints","kills","assists","damage","dbnos","survivalTime","extrasMatches","headshotKills","revives","heals","boosts","vehicleDestroys","roadKills","teamKills","walkDistance","rideDistance","swimDistance","longestKill","deaths","best"],"additionalProperties":false}}},"required":["tournament","matches","counted","players","teams"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/facts":{"get":{"summary":"Per-team FACTS analysis rows for a tournament","tags":["Tournaments"],"description":"Returns the FACTS rows posted via POST /webhooks/facts, one per team per match, over the completed, unvoided matches of a structureTree scope (bracketId / divisionId / roundId) or of one match of that scope (matchId = the source match id). `facts` is opaque, ingest-owned analysis data.","parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"matchId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"externalId":{"type":"string"},"startedAt":{"nullable":true,"type":"string"}},"required":["externalId","startedAt"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","properties":{"matchExternalId":{"type":"string"},"teamKey":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"facts":{"type":"object","additionalProperties":{}}},"required":["matchExternalId","teamKey","sanityTeamId","displayName","version","facts"],"additionalProperties":false}}},"required":["tournament","matches","rows"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/teams/{sanityTeamId}/facts":{"get":{"summary":"A team's own FACTS rows plus a compact projection of its lobbies","tags":["Tournaments"],"description":"Returns one team's FACTS rows (posted via POST /webhooks/facts) across its newest completed, unvoided matches, plus — for each of those matches — every other team's row projected down to team_id_in_match/factors/style/leaks, for a head-to-head view. Never 404s: a team with no rows gets an empty payload.","parameters":[{"schema":{"default":40,"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityTeamId","required":true,"description":"Sanity document id of the team"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"object","properties":{"sanityTeamId":{"type":"string"}},"required":["sanityTeamId"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"externalId":{"type":"string"},"startedAt":{"nullable":true,"type":"string"},"tournament":{"nullable":true,"type":"object","properties":{"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["sanityId","name"],"additionalProperties":false},"scope":{"type":"object","properties":{"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"}},"required":["bracketId","divisionId","roundId"],"additionalProperties":false}},"required":["externalId","startedAt","tournament","scope"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","properties":{"matchExternalId":{"type":"string"},"teamKey":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"facts":{"type":"object","additionalProperties":{}}},"required":["matchExternalId","teamKey","sanityTeamId","displayName","version","facts"],"additionalProperties":false}},"lobbies":{"type":"array","items":{"type":"object","properties":{"matchExternalId":{"type":"string"},"teams":{"type":"array","items":{"type":"object","properties":{"teamIdInMatch":{"type":"number"},"teamKey":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"factors":{},"style":{},"leaks":{}},"required":["teamIdInMatch","teamKey","sanityTeamId","displayName","factors","style","leaks"],"additionalProperties":false}}},"required":["matchExternalId","teams"],"additionalProperties":false}}},"required":["team","matches","rows","lobbies"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/games/{slug}/stats":{"get":{"summary":"Per-player and per-team statistics across every tournament of a game","tags":["Games"],"description":"The same rows as a tournament stats read, summed over the completed, unvoided team matches of every tournament of the game, optionally only those played since an instant (`since`). Individual ladder rows are left out.","parameters":[{"schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"in":"query","name":"since","required":false},{"schema":{"type":"string"},"in":"path","name":"slug","required":true,"description":"Game slug, e.g. pubg"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"game":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"],"additionalProperties":false},"since":{"nullable":true,"type":"string"},"counted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"tournaments":{"type":"array","items":{"type":"object","properties":{"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"},"matches":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["sanityId","name","matches"],"additionalProperties":false}},"players":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"accountId":{"nullable":true,"type":"string"},"teamKey":{"type":"string"},"teamName":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"matches":{"type":"number"},"wins":{"type":"number"},"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"extrasMatches":{"type":"number"},"headshotKills":{"nullable":true,"type":"number"},"revives":{"nullable":true,"type":"number"},"heals":{"nullable":true,"type":"number"},"boosts":{"nullable":true,"type":"number"},"weaponsAcquired":{"nullable":true,"type":"number"},"walkDistance":{"nullable":true,"type":"number"},"rideDistance":{"nullable":true,"type":"number"},"swimDistance":{"nullable":true,"type":"number"},"vehicleDestroys":{"nullable":true,"type":"number"},"roadKills":{"nullable":true,"type":"number"},"teamKills":{"nullable":true,"type":"number"},"longestKill":{"nullable":true,"type":"number"},"killStreaks":{"nullable":true,"type":"number"},"deaths":{"nullable":true,"type":"number"},"deathsByZone":{"nullable":true,"type":"number"},"suicides":{"nullable":true,"type":"number"},"earliestDeath":{"nullable":true,"type":"number"},"best":{"type":"object","properties":{"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"revives":{"nullable":true,"type":"number"},"headshotKills":{"nullable":true,"type":"number"}},"required":["kills","assists","damage","dbnos","survivalTime","revives","headshotKills"],"additionalProperties":false}},"required":["key","name","accountId","teamKey","teamName","sanityTeamId","matches","wins","kills","assists","damage","dbnos","survivalTime","extrasMatches","headshotKills","revives","heals","boosts","weaponsAcquired","walkDistance","rideDistance","swimDistance","vehicleDestroys","roadKills","teamKills","longestKill","killStreaks","deaths","deathsByZone","suicides","earliestDeath","best"],"additionalProperties":false}},"teams":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"sanityTeamId":{"nullable":true,"type":"string"},"matches":{"type":"number"},"wins":{"type":"number"},"top4":{"type":"number"},"top8":{"type":"number"},"avgPlacement":{"nullable":true,"type":"number"},"points":{"type":"number"},"placementPoints":{"type":"number"},"killPoints":{"type":"number"},"kills":{"type":"number"},"assists":{"type":"number"},"damage":{"type":"number"},"dbnos":{"type":"number"},"survivalTime":{"type":"number"},"extrasMatches":{"type":"number"},"headshotKills":{"nullable":true,"type":"number"},"revives":{"nullable":true,"type":"number"},"heals":{"nullable":true,"type":"number"},"boosts":{"nullable":true,"type":"number"},"vehicleDestroys":{"nullable":true,"type":"number"},"roadKills":{"nullable":true,"type":"number"},"teamKills":{"nullable":true,"type":"number"},"walkDistance":{"nullable":true,"type":"number"},"rideDistance":{"nullable":true,"type":"number"},"swimDistance":{"nullable":true,"type":"number"},"longestKill":{"nullable":true,"type":"number"},"deaths":{"nullable":true,"type":"number"},"best":{"type":"object","properties":{"kills":{"type":"number"},"damage":{"type":"number"},"points":{"type":"number"},"placement":{"nullable":true,"type":"number"}},"required":["kills","damage","points","placement"],"additionalProperties":false}},"required":["key","name","sanityTeamId","matches","wins","top4","top8","avgPlacement","points","placementPoints","killPoints","kills","assists","damage","dbnos","survivalTime","extrasMatches","headshotKills","revives","heals","boosts","vehicleDestroys","roadKills","teamKills","walkDistance","rideDistance","swimDistance","longestKill","deaths","best"],"additionalProperties":false}}},"required":["game","since","counted","tournaments","players","teams"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/games/{slug}/leaderboard":{"get":{"summary":"Get the cross-tournament leaderboard for a game","tags":["Games"],"description":"Returns aggregated standings (total score and matches played) per participant across every tournament of the game, ordered by total score descending. Sum aggregation only. Use participants=team or participants=person to rank only teams or only individual players (a game can carry both, e.g. CS2 tournaments and its open match queue).","parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"default":"all","type":"string","enum":["all","team","person"]},"in":"query","name":"participants","required":false},{"schema":{"type":"string"},"in":"path","name":"slug","required":true,"description":"Game slug, e.g. \"pubg\""}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"game":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"],"additionalProperties":false},"standings":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"totalScore":{"nullable":true,"type":"number"},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kills":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"placementPoints":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"damage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastMatchPoints":{"type":"number"},"lastMatchPlacement":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastMatchDamage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["key","displayName","totalScore","matchesPlayed"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["game","standings","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/games/{slug}/matches":{"get":{"summary":"List recent completed matches for a game","tags":["Games"],"description":"Returns the most recently completed matches for a game (both tournament and ladder), newest first, each with the two sides and — for CS2 — the per-map round scoreline.","parameters":[{"schema":{"default":5,"type":"integer","minimum":1,"maximum":50},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"path","name":"slug","required":true,"description":"Game slug, e.g. \"cs2\""}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"game":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"endedAt":{"nullable":true,"type":"string"},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"seriesFormat":{"nullable":true,"type":"string","enum":["bo1","bo3","bo5"]},"teamA":{"type":"object","properties":{"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"score":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["sanityTeamId","displayName","score"],"additionalProperties":false},"teamB":{"type":"object","properties":{"sanityTeamId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"score":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["sanityTeamId","displayName","score"],"additionalProperties":false},"maps":{"nullable":true,"type":"array","items":{"type":"object","properties":{"map":{"type":"string"},"scoreA":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreB":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["map","scoreA","scoreB"],"additionalProperties":false}}},"required":["id","tournamentId","endedAt","bestOf","seriesFormat","teamA","teamB","maps"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["game","matches","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/games/{slug}/person-ratings":{"get":{"summary":"Seeding ratings for a set of players in a game","tags":["Games"],"description":"Per-person Elo ratings built from head-to-head tournament results, for seeding a tournament field. Ranks are computed against every rated player in the game, not against the ids asked for. Players with no rated match are absent from the result — that is \"no history yet\", which is different from an empty read. `stale` is true when results have changed since the last rebuild; the numbers are still returned, and the caller is expected to say they are behind rather than present them as current.","parameters":[{"schema":{"type":"string"},"in":"query","name":"personIds","required":true,"description":"Comma-separated Sanity person ids"},{"schema":{"type":"string"},"in":"path","name":"slug","required":true,"description":"Game slug, e.g. \"ea-fc\""}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"game":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"],"additionalProperties":false},"stale":{"type":"boolean"},"rebuiltAt":{"nullable":true,"type":"string","format":"date-time"},"ratings":{"type":"array","items":{"type":"object","properties":{"personId":{"type":"string"},"rating":{"type":"number"},"rank":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"draws":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"losses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"form":{"type":"array","items":{"type":"string","enum":["W","D","L"]}},"lastMatchAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["personId","rating","rank","matchesPlayed","wins","draws","losses","form","lastMatchAt"],"additionalProperties":false}}},"required":["game","stale","rebuiltAt","ratings"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/games/{slug}/person-ratings/rebuild":{"post":{"summary":"Replay a game’s seeding ratings from its results","tags":["Games"],"description":"Recomputes every per-person rating in the game by replaying the head-to-head matches that are still standing, then clears the stale flag. Idempotent and deterministic: the same results always produce the same ratings. This is the answer to a corrected or voided result — Elo is path-dependent, so a retroactive change cannot be undone by subtracting a delta, and replaying is the only correct fix.","parameters":[{"schema":{"type":"string"},"in":"path","name":"slug","required":true,"description":"Game slug, e.g. \"ea-fc\""}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"game":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"],"additionalProperties":false},"matchesRated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"playersRated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rebuiltAt":{"type":"string","format":"date-time"}},"required":["game","matchesRated","playersRated","rebuiltAt"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/structure":{"post":{"summary":"Write a tournament structure (idempotent, reconciling)","tags":["Tournaments"],"description":"Upserts the brackets/divisions/rounds/matches hierarchy by structureTree node id. Re-publishing reconciles removed nodes — but never deletes structure that has results; those orphan node ids are returned in `orphansSkipped` instead.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schema_version":{"type":"number","enum":[1]},"brackets":{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"name":{"type":"string"},"order":{"type":"number"},"divisions":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"name":{"type":"string"},"order":{"type":"number"},"maxTeams":{"type":"number"},"rounds":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"name":{"type":"string"},"order":{"type":"number"},"matches":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"order":{"type":"number"},"name":{"type":"string"},"status":{"type":"string"}},"required":["id","order"]}}},"required":["id","name","order"]}}},"required":["id","name","order"]}}},"required":["id","name","order"]}}},"required":["schema_version","brackets"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"counts":{"type":"object","properties":{"brackets":{"type":"number"},"divisions":{"type":"number"},"rounds":{"type":"number"},"matches":{"type":"number"}},"required":["brackets","divisions","rounds","matches"],"additionalProperties":false},"reconciled":{"type":"boolean"},"orphansSkipped":{"type":"array","items":{"type":"string"}}},"required":["counts","reconciled","orphansSkipped"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations":{"get":{"summary":"List a tournament’s registrations","tags":["Tournaments"],"description":"Defaults to team registrations (pre-existing consumers never see individual rows); pass participantKind=individual or 'all' for EA FC 1v1 entries.","parameters":[{"schema":{"default":"team","type":"string","enum":["team","individual","all"]},"in":"query","name":"participantKind","required":false},{"schema":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registrations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"teamSanityId":{"nullable":true,"type":"string"},"personSanityId":{"nullable":true,"type":"string"},"checkedInBySanityId":{"nullable":true,"type":"string"},"divisionStructureNodeId":{"nullable":true,"type":"string"},"divisionName":{"nullable":true,"type":"string"},"lineupLock":{"nullable":true,"type":"object","properties":{"lockedAt":{"type":"string","format":"date-time"},"source":{"type":"string","enum":["self","admin_force","schedule"]},"players":{"type":"array","items":{"type":"object","properties":{"personSanityId":{"nullable":true,"type":"string"},"gameAccountId":{"nullable":true,"type":"string"}},"required":["personSanityId","gameAccountId"],"additionalProperties":false}}},"required":["lockedAt","source","players"],"additionalProperties":false}},"required":["id","tournamentId","teamId","participantKind","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decisionReason","waitlistPosition","teamSanityId","personSanityId","checkedInBySanityId","divisionStructureNodeId","divisionName","lineupLock"],"additionalProperties":false}}},"required":["registrations"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Register a team (idempotent)","tags":["Tournaments"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1}},"required":["teamSanityId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"personUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decidedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","teamId","participantKind","personUserId","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decidedByUserId","decisionReason","waitlistPosition","createdAt","updatedAt"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/individual":{"post":{"summary":"Register an individual participant (idempotent)","tags":["Tournaments"],"description":"EA FC 1v1 entry. Starts as pending unless autoApprove is true (then registered).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"personSanityId":{"type":"string","minLength":1},"displayName":{"type":"string","minLength":1},"metadata":{"type":"object","additionalProperties":{}},"autoApprove":{"default":false,"type":"boolean"}},"required":["personSanityId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"personUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decidedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","teamId","participantKind","personUserId","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decidedByUserId","decisionReason","waitlistPosition","createdAt","updatedAt"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/divisions":{"post":{"summary":"Place registrations into divisions","tags":["Tournaments"],"description":"Assigns each named registration to a division by its structureTree node id, or unassigns it with null. Only the entries named are touched. Applied in one transaction: if any division id or registration is unknown, nothing is written. A division id resolves only once the structure has been published (materialized).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assignments":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1},"personSanityId":{"type":"string","minLength":1},"divisionStructureNodeId":{"nullable":true,"type":"string","minLength":1}},"required":["divisionStructureNodeId"]}}},"required":["assignments"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"assigned":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cleared":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["assigned","cleared"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/decide":{"post":{"summary":"Decide (approve/reject/waitlist) a registration","tags":["Tournaments"],"description":"Applies an admin decision to a team or individual registration. A withdrawn registration cannot be decided (409 invalid_status_transition).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1},"personSanityId":{"type":"string","minLength":1},"status":{"type":"string","enum":["approved","rejected","waitlist","pending"]},"reason":{"type":"string","minLength":1},"byPersonSanityId":{"type":"string","minLength":1},"waitlistPosition":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["status"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"personUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decidedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","teamId","participantKind","personUserId","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decidedByUserId","decisionReason","waitlistPosition","createdAt","updatedAt"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/withdraw":{"post":{"summary":"Withdraw a team","tags":["Tournaments"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1}},"required":["teamSanityId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"personUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decidedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","teamId","participantKind","personUserId","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decidedByUserId","decisionReason","waitlistPosition","createdAt","updatedAt"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/checkin":{"post":{"summary":"Check in a team","tags":["Tournaments"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1},"byPersonSanityId":{"type":"string","minLength":1}},"required":["teamSanityId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"teamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"participantKind":{"type":"string","enum":["team","individual"]},"personUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["registered","withdrawn","pending","approved","waitlist","rejected"]},"registeredAt":{"type":"string","format":"date-time"},"checkedInAt":{"nullable":true,"type":"string","format":"date-time"},"checkedInByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decidedAt":{"nullable":true,"type":"string","format":"date-time"},"decidedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"decisionReason":{"nullable":true,"type":"string"},"waitlistPosition":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","teamId","participantKind","personUserId","displayName","status","registeredAt","checkedInAt","checkedInByUserId","decidedAt","decidedByUserId","decisionReason","waitlistPosition","createdAt","updatedAt"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/registrations/lineup-lock":{"post":{"summary":"Lock (or relock) a team’s lineup","tags":["Tournaments"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamSanityId":{"type":"string","minLength":1},"source":{"type":"string","enum":["self","admin_force","schedule"]},"byPersonSanityId":{"type":"string","minLength":1},"players":{"default":[],"type":"array","items":{"type":"object","properties":{"personSanityId":{"type":"string","minLength":1},"gameAccountId":{"nullable":true,"type":"string"}},"required":["personSanityId"]}}},"required":["teamSanityId","source"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"lineupLock":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"registrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"lockedAt":{"type":"string","format":"date-time"},"source":{"type":"string","enum":["self","admin_force","schedule"]},"lockedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","registrationId","lockedAt","source","lockedByUserId","createdAt"],"additionalProperties":false}},"required":["lineupLock"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/head-to-head-matches":{"post":{"summary":"Create a head-to-head match between two individual registrations","tags":["Football"],"description":"Both persons must hold an approved (or registered) individual registration in the tournament. Idempotent on externalId when given.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","minLength":1},"bracketId":{"type":"string","minLength":1},"divisionId":{"type":"string","minLength":1},"roundId":{"type":"string","minLength":1},"roundNumber":{"type":"integer","minimum":1,"maximum":9007199254740991},"homePersonSanityId":{"type":"string","minLength":1},"awayPersonSanityId":{"type":"string","minLength":1},"scheduledAt":{},"metadata":{"nullable":true,"type":"object","additionalProperties":{}}},"required":["homePersonSanityId","awayPersonSanityId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List a tournament’s head-to-head matches","tags":["Football"],"parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"matches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"home":{"type":"object","properties":{"registrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"personSanityId":{"nullable":true,"type":"string"},"displayName":{"nullable":true,"type":"string"}},"required":["registrationId","personSanityId","displayName"],"additionalProperties":false},"away":{"type":"object","properties":{"registrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"personSanityId":{"nullable":true,"type":"string"},"displayName":{"nullable":true,"type":"string"}},"required":["registrationId","personSanityId","displayName"],"additionalProperties":false}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt","home","away"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["tournament","matches","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/report":{"post":{"summary":"Report a head-to-head match result (once)","tags":["Football"],"description":"Completes an unvoided scheduled/live match with a final score. A second report returns 409 already_reported — use PATCH …/result to correct. Set walkover=true when the match was awarded rather than played (an opponent who did not turn up): it is stored as `walkover` instead of `completed`, so it stays distinguishable everywhere it renders while counting the same in the table. `source` records who or what decided the result — an admin, both players agreeing, one unopposed report, or a deadline passing with nobody reporting. It is kept on the result event so a later correction can see that no human reported the original.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scoreHome":{"type":"integer","minimum":0,"maximum":9007199254740991},"scoreAway":{"type":"integer","minimum":0,"maximum":9007199254740991},"byPersonSanityId":{"type":"string","minLength":1},"walkover":{"default":false,"type":"boolean"},"source":{"default":"admin","type":"string","enum":["admin","players","single_report","deadline"]}},"required":["scoreHome","scoreAway"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/report-as-player":{"post":{"summary":"Report a result as one of the two players (T4)","tags":["Football"],"description":"Records what one side says the result was, and settles the match when both have. Both agreeing completes it with source `players`; both reporting different scores makes it `disputed` with no score and both claims kept for an admin; one reporting leaves the match alone until the deadline passes — that is `POST …/resolve-reports`, not this. One claim per side and a claim is final: re-sending the same score answers as it did the first time, a different one returns 409 already_reported_by_side. A person who is neither side gets 403, and a match already disputed gets 409 match_disputed — only an admin decides from there. The score is always home-then-away of the match, not the reporter’s own first. `byPersonSanityId` is an assertion, not proof: this service has no player login, so the caller must bind it to its own authenticated session and never take it from a browser.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"byPersonSanityId":{"type":"string","minLength":1},"scoreHome":{"type":"integer","minimum":0,"maximum":9007199254740991},"scoreAway":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["byPersonSanityId","scoreHome","scoreAway"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false},"outcome":{"type":"string","enum":["awaiting_opponent","agreed","disputed"]},"reports":{"type":"array","items":{"type":"object","properties":{"registrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"personSanityId":{"nullable":true,"type":"string"},"displayName":{"nullable":true,"type":"string"},"scoreHome":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reportedAt":{"type":"string","format":"date-time"}},"required":["registrationId","personSanityId","displayName","scoreHome","scoreAway","reportedAt"],"additionalProperties":false}}},"required":["match","outcome","reports"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/resolve-reports":{"post":{"summary":"Settle a match whose reporting deadline has passed (T4)","tags":["Football"],"description":"One side reported and the other stayed silent: the one report stands, sourced `single_report` so it is distinguishable forever from a result both sides confirmed. Answers `none` and changes nothing when the match is already settled, voided, or nobody reported — the caller then awards the no-show as before. Safe to re-run. This service knows nothing about the deadline: it settles a lone report the moment it is asked, so the caller has to be the sweep that owns the deadline. Never reachable by a player — one call the instant they report would settle their own score before the opponent could disagree.","parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false},"outcome":{"type":"string","enum":["single_report","agreed","disputed","none"]}},"required":["match","outcome"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/reports":{"get":{"summary":"What each side claimed the result was (T4)","tags":["Football"],"description":"Both claims, oldest first — the evidence an admin resolves a dispute from. They outlive the decision: correcting a result does not make the claims untrue. Show this to an admin, or to a player who has already claimed. A player who has not could read the opponent’s score and submit it verbatim, which is exactly the manufactured agreement the one-claim-per-side rule prevents.","parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"registrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"personSanityId":{"nullable":true,"type":"string"},"displayName":{"nullable":true,"type":"string"},"scoreHome":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reportedAt":{"type":"string","format":"date-time"}},"required":["registrationId","personSanityId","displayName","scoreHome","scoreAway","reportedAt"],"additionalProperties":false}}},"required":["reports"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/result":{"patch":{"summary":"Correct an already-reported result (audited)","tags":["Football"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scoreHome":{"type":"integer","minimum":0,"maximum":9007199254740991},"scoreAway":{"type":"integer","minimum":0,"maximum":9007199254740991},"reason":{"type":"string","minLength":1},"byPersonSanityId":{"type":"string","minLength":1}},"required":["scoreHome","scoreAway","reason"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/void":{"post":{"summary":"Void or restore a head-to-head match (audited)","tags":["Football"],"description":"A voided match is excluded from standings but kept for audit. `onlyIfStatusIn` makes the write conditional — an unattended caller (a deadline sweep) passes [\"scheduled\",\"live\"] so it cannot annul a result an admin entered between its read and its write; the match then answers 409 already_reported instead. `source` records who or what decided it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voided":{"default":true,"type":"boolean"},"reason":{"type":"string","minLength":1},"byPersonSanityId":{"type":"string","minLength":1},"onlyIfStatusIn":{"minItems":1,"type":"array","items":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]}},"source":{"default":"admin","type":"string","enum":["admin","players","single_report","deadline"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/head-to-head-standings":{"get":{"summary":"Get the football league table for a tournament","tags":["Football"],"description":"Computed from non-voided completed/walkover matches; every approved/registered individual registration appears (zero row when unplayed). Norwegian column mapping: K=played, V=wins, U=draws, T=losses, MF=goalsFor, MM=goalsAgainst, +/-=goalDiff, P=points.","parameters":[{"schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"in":"query","name":"offset","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"roundId","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"standings":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"key":{"type":"string"},"registrationId":{"type":"string"},"personSanityId":{"nullable":true,"type":"string"},"teamSanityId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"played":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"draws":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"losses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goalsFor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goalsAgainst":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goalDiff":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"points":{"type":"number"},"form":{"type":"array","items":{"type":"string","enum":["W","D","L"]}}},"required":["rank","key","registrationId","personSanityId","teamSanityId","displayName","played","wins","draws","losses","goalsFor","goalsAgainst","goalDiff","points","form"],"additionalProperties":false}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","limit","offset"],"additionalProperties":false}},"required":["tournament","standings","meta"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/reschedule-proposals":{"post":{"summary":"Ask the opponent to move this match (T6)","tags":["Football"],"description":"Stores a pending proposal and changes nothing else: the match keeps its kick-off until the opponent accepts, because a half-moved fixture is one every reader has to know to ignore. One open ask per side — re-sending the same time is a retry and answers as it did the first time, a different one while the first is open is refused. `byPersonSanityId` says who is asking and must be one of the two sides; omit it with `byAdmin` only for an arranger, who is bound by neither the agreement nor the round window. **Whether the time is inside the round window is the caller's to enforce** — the window lives on the structure tree, not here.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"proposedStart":{},"byPersonSanityId":{"type":"string","minLength":1},"message":{"nullable":true,"type":"string","maxLength":2000},"respondBy":{"nullable":true}},"required":["proposedStart","byPersonSanityId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"proposal":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false}},"required":["proposal"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"The reschedule trail for one match (T6)","tags":["Football"],"description":"Who proposed what, when, and what happened to it — oldest first, nothing filtered out. This is the admin insight the feature owes: a declined ask and a superseded one are part of the story of a match that moved twice. A `pending` row past its `respondBy` reads as `expired`.","parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"proposals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false}}},"required":["proposals"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-reschedule-proposals/{id}/respond":{"post":{"summary":"Accept or decline a proposed new time (T6)","tags":["Football"],"description":"Accepting is the only thing that moves the match, and it happens in the same transaction that closes the proposal — so nobody can see an accepted proposal beside a fixture still at its old time. Other open proposals on the match become `superseded`, not `declined`: nobody refused them. Only the side that did NOT propose may answer, and there is no override: the proposer accepting their own ask would be moving the match alone, which is the one thing this mechanism exists to prevent. An arranger does not answer for a player — they move the match themselves via `PATCH /head-to-head-matches/:id/scheduled-at`, which is recorded as theirs.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accept":{"type":"boolean"},"byPersonSanityId":{"type":"string","minLength":1}},"required":["accept","byPersonSanityId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"proposal":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false},"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["proposal","match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-reschedule-proposals/{id}/cancel":{"post":{"summary":"Withdraw your own proposal (T6)","tags":["Football"],"description":"Only the side that proposed it, and only while it is still open. Cancelling somebody else’s ask is not the same as declining it — declining is an answer the proposer gets to see, this would erase the question — so it is refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"byPersonSanityId":{"type":"string","minLength":1}},"required":["byPersonSanityId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"proposal":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false}},"required":["proposal"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/head-to-head-matches/{id}/scheduled-at":{"patch":{"summary":"Move a match outright, as an arranger (T6)","tags":["Football"],"description":"No agreement and no window: an admin is bound by neither. It still writes a proposal row, already accepted and flagged `byAdmin`, and supersedes the players’ open asks — otherwise the reschedule trail has a hole exactly where an arranger overrode the players, which is the case somebody will ask about.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledAt":{},"byPersonSanityId":{"type":"string","minLength":1},"reason":{"nullable":true,"type":"string","maxLength":2000}},"required":["scheduledAt","byPersonSanityId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"proposal":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false},"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"roundNumber":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"externalId":{"nullable":true,"type":"string"},"homeRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","walkover","disputed","cancelled"]},"scoreHome":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scoreAway":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"voided":{"type":"boolean"},"reportedByUserId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reportedAt":{"nullable":true,"type":"string","format":"date-time"},"metadata":{"nullable":true},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tournamentId","bracketId","divisionId","roundId","roundNumber","externalId","homeRegistrationId","awayRegistrationId","status","scoreHome","scoreAway","voided","reportedByUserId","reportedAt","metadata","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["proposal","match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/head-to-head-reschedule-proposals":{"get":{"summary":"Every open proposal in a tournament (T6)","tags":["Football"],"description":"The open asks across a whole fixture list, so a page can show \"waiting for your answer\" on the rows that have one without a call per row. Only answerable proposals: a `pending` row past its `respondBy` is left out, because a question nobody can answer is not an open question.","parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"sanityId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tournament":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityId":{"nullable":true,"type":"string"},"name":{"type":"string"}},"required":["id","sanityId","name"],"additionalProperties":false},"proposals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"headToHeadMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByRegistrationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"proposedByPersonSanityId":{"nullable":true,"type":"string"},"proposedByDisplayName":{"nullable":true,"type":"string"},"proposedStart":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","accepted","declined","cancelled","superseded","expired"]},"message":{"nullable":true,"type":"string"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"byAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","headToHeadMatchId","proposedByRegistrationId","proposedByPersonSanityId","proposedByDisplayName","proposedStart","status","message","respondBy","respondedAt","byAdmin","createdAt"],"additionalProperties":false}}},"required":["tournament","proposals"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders":{"post":{"summary":"Create a ladder","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"gameSlug":{"type":"string","minLength":1},"slug":{"type":"string","minLength":1,"pattern":"^[a-z0-9-]+$"},"name":{"type":"string","minLength":1},"region":{"type":"string","minLength":1},"seasonNumber":{"type":"integer","minimum":0,"maximum":9007199254740991},"challengeModes":{"type":"object","properties":{"direct":{"type":"boolean"},"open":{"type":"boolean"},"smart":{"type":"boolean"}},"required":["direct","open","smart"]},"ratingConfig":{},"rosterConfig":{},"rulesConfig":{},"startsAt":{"nullable":true},"endsAt":{"nullable":true}},"required":["gameSlug","slug","name","region"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sanityId":{"nullable":true,"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]},"challengeModes":{"nullable":true},"ratingConfig":{"nullable":true},"rosterConfig":{"nullable":true},"rulesConfig":{"nullable":true},"startsAt":{"nullable":true,"type":"string","format":"date-time"},"endsAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","sanityId","slug","name","region","seasonNumber","status","challengeModes","ratingConfig","rosterConfig","rulesConfig","startsAt","endsAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List ladders","tags":["Ladders"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"region","required":false},{"schema":{"type":"string","enum":["draft","active","finals","archived"]},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"gameSlug","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sanityId":{"nullable":true,"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]},"challengeModes":{"nullable":true},"ratingConfig":{"nullable":true},"rosterConfig":{"nullable":true},"rulesConfig":{"nullable":true},"startsAt":{"nullable":true,"type":"string","format":"date-time"},"endsAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","sanityId","slug","name","region","seasonNumber","status","challengeModes","ratingConfig","rosterConfig","rulesConfig","startsAt","endsAt","createdAt","updatedAt"],"additionalProperties":false}}},"required":["ladders"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}":{"get":{"summary":"Get a ladder by slug","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sanityId":{"nullable":true,"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]},"challengeModes":{"nullable":true},"ratingConfig":{"nullable":true},"rosterConfig":{"nullable":true},"rulesConfig":{"nullable":true},"startsAt":{"nullable":true,"type":"string","format":"date-time"},"endsAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","sanityId","slug","name","region","seasonNumber","status","challengeModes","ratingConfig","rosterConfig","rulesConfig","startsAt","endsAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Update a ladder (name, region, schedule, configs — not lifecycle)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"region":{"type":"string","minLength":1},"challengeModes":{"type":"object","properties":{"direct":{"type":"boolean"},"open":{"type":"boolean"},"smart":{"type":"boolean"}},"required":["direct","open","smart"]},"ratingConfig":{},"rosterConfig":{},"rulesConfig":{},"startsAt":{"nullable":true},"endsAt":{"nullable":true}}}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sanityId":{"nullable":true,"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]},"challengeModes":{"nullable":true},"ratingConfig":{"nullable":true},"rosterConfig":{"nullable":true},"rulesConfig":{"nullable":true},"startsAt":{"nullable":true,"type":"string","format":"date-time"},"endsAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","sanityId","slug","name","region","seasonNumber","status","challengeModes","ratingConfig","rosterConfig","rulesConfig","startsAt","endsAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/teams":{"post":{"summary":"Enroll a team in a ladder (idempotent)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sanityTeamId":{"type":"string","minLength":1},"displayName":{"type":"string","minLength":1}},"required":["sanityTeamId","displayName"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityTeamId":{"type":"string"},"displayName":{"type":"string"},"rating":{"type":"number"},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"losses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","inactive","withdrawn"]}},"required":["id","ladderId","sanityTeamId","displayName","rating","matchesPlayed","wins","losses","status"],"additionalProperties":false}},"required":["team"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/teams/withdraw":{"post":{"summary":"Withdraw a team from a ladder","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sanityTeamId":{"type":"string","minLength":1}},"required":["sanityTeamId"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityTeamId":{"type":"string"},"displayName":{"type":"string"},"rating":{"type":"number"},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"losses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","inactive","withdrawn"]}},"required":["id","ladderId","sanityTeamId","displayName","rating","matchesPlayed","wins","losses","status"],"additionalProperties":false}},"required":["team"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/leaderboard":{"get":{"summary":"Rating-ordered ladder leaderboard","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ladderTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityTeamId":{"type":"string"},"displayName":{"type":"string"},"rating":{"type":"number"},"matchesPlayed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wins":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"losses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"form":{"nullable":true},"weeklyDelta":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["rank","ladderTeamId","sanityTeamId","displayName","rating","matchesPlayed","wins","losses","form","weeklyDelta"],"additionalProperties":false}}},"required":["entries"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/rating-preview":{"get":{"summary":"Expected rating change if two teams played (the pre-match +X / −Y)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"query","name":"home","required":true},{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"query","name":"away","required":true},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"home":{"type":"object","properties":{"win":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"loss":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["win","loss"],"additionalProperties":false},"away":{"type":"object","properties":{"win":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"loss":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["win","loss"],"additionalProperties":false}},"required":["home","away"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/challenges":{"post":{"summary":"Create a challenge (direct / open / smart)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"bestOf":{"type":"integer","minimum":1,"maximum":7},"message":{"type":"string","maxLength":280},"respondBy":{"nullable":true},"slotInstanceId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["challengerTeamId","mode"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"status":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"nullable":true,"type":"string"},"proposedAt":{"type":"string","format":"date-time"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengerTeamId","challengedTeamId","mode","status","bestOf","message","proposedAt","respondBy","respondedAt","scheduledAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["challenge"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List challenges (lazily expires stale pending ones)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"query","name":"teamId","required":false},{"schema":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"challenges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"status":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"nullable":true,"type":"string"},"proposedAt":{"type":"string","format":"date-time"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengerTeamId","challengedTeamId","mode","status","bestOf","message","proposedAt","respondBy","respondedAt","scheduledAt","createdAt","updatedAt"],"additionalProperties":false}}},"required":["challenges"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/challenges/expire":{"post":{"summary":"Sweep pending challenges past their defense-window deadline","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"expired":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["expired"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/teams/{teamId}/suggestions":{"get":{"summary":"Smart-suggested opponents ranked by rating proximity","tags":["Ladders"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":25},"in":"query","name":"limit","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true},{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"teamId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"suggestions":{"type":"array","items":{"type":"object","properties":{"ladderTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"type":"string"},"rating":{"type":"number"},"ratingGap":{"type":"number"}},"required":["ladderTeamId","displayName","rating","ratingGap"],"additionalProperties":false}}},"required":["suggestions"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/challenges/{id}/accept":{"post":{"summary":"Accept a pending challenge (spawns a scheduled match)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptingTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"status":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"nullable":true,"type":"string"},"proposedAt":{"type":"string","format":"date-time"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengerTeamId","challengedTeamId","mode","status","bestOf","message","proposedAt","respondBy","respondedAt","scheduledAt","createdAt","updatedAt"],"additionalProperties":false},"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"homeTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cs2ExternalId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengeId","homeTeamId","awayTeamId","matchId","cs2ExternalId","status","bestOf","homeScore","awayScore","winnerTeamId","scheduledAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["challenge","match"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/challenges/{id}/decline":{"post":{"summary":"Decline a pending challenge","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"status":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"nullable":true,"type":"string"},"proposedAt":{"type":"string","format":"date-time"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengerTeamId","challengedTeamId","mode","status","bestOf","message","proposedAt","respondBy","respondedAt","scheduledAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["challenge"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/challenges/{id}/cancel":{"post":{"summary":"Cancel a pending challenge (by the challenger)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengerTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengedTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mode":{"type":"string","enum":["direct","open","smart"]},"status":{"type":"string","enum":["pending","accepted","declined","expired","cancelled","played"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"nullable":true,"type":"string"},"proposedAt":{"type":"string","format":"date-time"},"respondBy":{"nullable":true,"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengerTeamId","challengedTeamId","mode","status","bestOf","message","proposedAt","respondBy","respondedAt","scheduledAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["challenge"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/matches":{"get":{"summary":"List ladder matches","tags":["Ladders"],"parameters":[{"schema":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"query","name":"teamId","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"matches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"homeTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cs2ExternalId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"slotEndsAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"winnerRatingDelta":{"nullable":true,"type":"number"}},"required":["id","ladderId","challengeId","homeTeamId","awayTeamId","matchId","cs2ExternalId","status","bestOf","homeScore","awayScore","winnerTeamId","scheduledAt","slotEndsAt","playedAt","createdAt","updatedAt","winnerRatingDelta"],"additionalProperties":false}}},"required":["matches"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}":{"get":{"summary":"Get a ladder match","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"homeTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cs2ExternalId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"slotEndsAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengeId","homeTeamId","awayTeamId","matchId","cs2ExternalId","status","bestOf","homeScore","awayScore","winnerTeamId","scheduledAt","slotEndsAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}/attach":{"post":{"summary":"Correlate a provisioned CS2 matchroom and flip the match live","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cs2ExternalId":{"type":"string","minLength":1}},"required":["cs2ExternalId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"homeTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"awayTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"matchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cs2ExternalId":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"bestOf":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scheduledAt":{"nullable":true,"type":"string","format":"date-time"},"slotEndsAt":{"nullable":true,"type":"string","format":"date-time"},"playedAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","challengeId","homeTeamId","awayTeamId","matchId","cs2ExternalId","status","bestOf","homeScore","awayScore","winnerTeamId","scheduledAt","slotEndsAt","playedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["match"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}/report":{"post":{"summary":"Report a match result — settles + applies rating","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"homeScore":{"type":"integer","minimum":0,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["homeScore","awayScore"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id","status","homeScore","awayScore","winnerTeamId"],"additionalProperties":false},"rating":{"type":"object","properties":{"home":{"type":"object","properties":{"before":{"type":"number"},"after":{"type":"number"},"delta":{"type":"number"}},"required":["before","after","delta"],"additionalProperties":false},"away":{"type":"object","properties":{"before":{"type":"number"},"after":{"type":"number"},"delta":{"type":"number"}},"required":["before","after","delta"],"additionalProperties":false}},"required":["home","away"],"additionalProperties":false}},"required":["match","rating"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}/no-show":{"post":{"summary":"Settle a match as a no-show forfeit","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"noShowTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["noShowTeamId"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"match":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["scheduled","live","completed","no_show","disputed","cancelled"]},"homeScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"awayScore":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"winnerTeamId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id","status","homeScore","awayScore","winnerTeamId"],"additionalProperties":false},"rating":{"type":"object","properties":{"home":{"type":"object","properties":{"before":{"type":"number"},"after":{"type":"number"},"delta":{"type":"number"}},"required":["before","after","delta"],"additionalProperties":false},"away":{"type":"object","properties":{"before":{"type":"number"},"after":{"type":"number"},"delta":{"type":"number"}},"required":["before","after","delta"],"additionalProperties":false}},"required":["home","away"],"additionalProperties":false}},"required":["match","rating"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}/dispute":{"post":{"summary":"Raise a dispute against a match","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"raisedByTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reason":{"type":"string","minLength":1,"maxLength":2000},"evidence":{}},"required":["raisedByTeamId","reason"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"dispute":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"raisedByTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["open","resolved","dismissed"]},"reason":{"type":"string"},"evidence":{"nullable":true},"resolution":{"nullable":true,"type":"string"},"resolvedBy":{"nullable":true,"type":"string"},"openedAt":{"type":"string","format":"date-time"},"resolvedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","ladderMatchId","raisedByTeamId","status","reason","evidence","resolution","resolvedBy","openedAt","resolvedAt"],"additionalProperties":false}},"required":["dispute"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-matches/{id}/disputes":{"get":{"summary":"List disputes against a match","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"disputes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"raisedByTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["open","resolved","dismissed"]},"reason":{"type":"string"},"evidence":{"nullable":true},"resolution":{"nullable":true,"type":"string"},"resolvedBy":{"nullable":true,"type":"string"},"openedAt":{"type":"string","format":"date-time"},"resolvedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","ladderMatchId","raisedByTeamId","status","reason","evidence","resolution","resolvedBy","openedAt","resolvedAt"],"additionalProperties":false}}},"required":["disputes"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-disputes/{id}/resolve":{"post":{"summary":"Resolve or dismiss a dispute","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["resolved","dismissed"]},"resolution":{"type":"string","maxLength":2000},"resolvedBy":{"type":"string"}},"required":["status"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"dispute":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"raisedByTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["open","resolved","dismissed"]},"reason":{"type":"string"},"evidence":{"nullable":true},"resolution":{"nullable":true,"type":"string"},"resolvedBy":{"nullable":true,"type":"string"},"openedAt":{"type":"string","format":"date-time"},"resolvedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","ladderMatchId","raisedByTeamId","status","reason","evidence","resolution","resolvedBy","openedAt","resolvedAt"],"additionalProperties":false}},"required":["dispute"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/recruitment":{"post":{"summary":"Create a recruitment post (LFT / LFP)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["lft","lfp"]},"displayName":{"type":"string","minLength":1},"sanityTeamId":{"nullable":true,"type":"string"},"sanityPersonId":{"nullable":true,"type":"string"},"role":{"type":"string"},"skillLevel":{"type":"string"},"languages":{"type":"array","items":{"type":"string"}},"availability":{"type":"string"},"ambition":{"type":"string"},"note":{"type":"string","maxLength":2000}},"required":["kind","displayName"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["lft","lfp"]},"sanityTeamId":{"nullable":true,"type":"string"},"sanityPersonId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"role":{"nullable":true,"type":"string"},"skillLevel":{"nullable":true,"type":"string"},"languages":{"nullable":true},"availability":{"nullable":true,"type":"string"},"ambition":{"nullable":true,"type":"string"},"note":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["open","filled","closed"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","kind","sanityTeamId","sanityPersonId","displayName","role","skillLevel","languages","availability","ambition","note","status","createdAt","updatedAt"],"additionalProperties":false}},"required":["post"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List recruitment posts","tags":["Ladders"],"parameters":[{"schema":{"type":"string","enum":["lft","lfp"]},"in":"query","name":"kind","required":false},{"schema":{"type":"string","enum":["open","filled","closed"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["lft","lfp"]},"sanityTeamId":{"nullable":true,"type":"string"},"sanityPersonId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"role":{"nullable":true,"type":"string"},"skillLevel":{"nullable":true,"type":"string"},"languages":{"nullable":true},"availability":{"nullable":true,"type":"string"},"ambition":{"nullable":true,"type":"string"},"note":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["open","filled","closed"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","kind","sanityTeamId","sanityPersonId","displayName","role","skillLevel","languages","availability","ambition","note","status","createdAt","updatedAt"],"additionalProperties":false}}},"required":["posts"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/recruitment/{id}/close":{"post":{"summary":"Close (or mark filled) a recruitment post","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["closed","filled"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["lft","lfp"]},"sanityTeamId":{"nullable":true,"type":"string"},"sanityPersonId":{"nullable":true,"type":"string"},"displayName":{"type":"string"},"role":{"nullable":true,"type":"string"},"skillLevel":{"nullable":true,"type":"string"},"languages":{"nullable":true},"availability":{"nullable":true,"type":"string"},"ambition":{"nullable":true,"type":"string"},"note":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["open","filled","closed"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","ladderId","kind","sanityTeamId","sanityPersonId","displayName","role","skillLevel","languages","availability","ambition","note","status","createdAt","updatedAt"],"additionalProperties":false}},"required":["post"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/recruitment/{id}/trials":{"post":{"summary":"Send a trial request against a post","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fromSanityId":{"type":"string","minLength":1},"fromDisplayName":{"type":"string","minLength":1},"message":{"type":"string","maxLength":2000}},"required":["fromSanityId","fromDisplayName"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"trial":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"postId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"fromSanityId":{"type":"string"},"fromDisplayName":{"type":"string"},"message":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["pending","accepted","declined"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","postId","fromSanityId","fromDisplayName","message","status","createdAt","respondedAt"],"additionalProperties":false}},"required":["trial"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List trial requests for a post","tags":["Ladders"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"trials":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"postId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"fromSanityId":{"type":"string"},"fromDisplayName":{"type":"string"},"message":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["pending","accepted","declined"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","postId","fromSanityId","fromDisplayName","message","status","createdAt","respondedAt"],"additionalProperties":false}}},"required":["trials"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/trials/{id}/respond":{"post":{"summary":"Accept or decline a trial request","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","declined"]}},"required":["status"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"trial":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"postId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"fromSanityId":{"type":"string"},"fromDisplayName":{"type":"string"},"message":{"nullable":true,"type":"string"},"status":{"type":"string","enum":["pending","accepted","declined"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"nullable":true,"type":"string","format":"date-time"}},"required":["id","postId","fromSanityId","fromDisplayName","message","status","createdAt","respondedAt"],"additionalProperties":false}},"required":["trial"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/season/start":{"post":{"summary":"Start the season (draft → active)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]}},"required":["id","slug","seasonNumber","status"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/season/finalize":{"post":{"summary":"Move the season to finals (active → finals)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]}},"required":["id","slug","seasonNumber","status"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/season/roll":{"post":{"summary":"Roll to the next season (bump + rating soft-reset)","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]}},"required":["id","slug","seasonNumber","status"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/season/archive":{"post":{"summary":"Archive the season","tags":["Ladders"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ladder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"seasonNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["draft","active","finals","archived"]}},"required":["id","slug","seasonNumber","status"],"additionalProperties":false}},"required":["ladder"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/finalists":{"get":{"summary":"Seeded top-N finalists (?top → rules_config.finalistCount → 8) for final seeding","tags":["Ladders"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":128},"in":"query","name":"top","required":false},{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"finalists":{"type":"array","items":{"type":"object","properties":{"seed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ladderTeamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"displayName":{"type":"string"},"rating":{"type":"number"}},"required":["seed","ladderTeamId","displayName","rating"],"additionalProperties":false}}},"required":["finalists"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladders/{slug}/teams/{teamId}/roster":{"post":{"summary":"Lock a team’s core roster (Steam-gated)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roster":{"type":"array","items":{"type":"object","properties":{"sanityPersonId":{"type":"string","minLength":1},"steamId":{"nullable":true,"type":"string"},"displayName":{"nullable":true,"type":"string"}},"required":["sanityPersonId"]}}},"required":["roster"]}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"slug","required":true},{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"teamId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"sanityTeamId":{"type":"string"},"displayName":{"type":"string"},"rating":{"type":"number"},"status":{"type":"string","enum":["active","inactive","withdrawn"]},"coreRoster":{"nullable":true}},"required":["id","ladderId","sanityTeamId","displayName","rating","status","coreRoster"],"additionalProperties":false}},"required":["team"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/ladder-teams/{id}/penalize":{"post":{"summary":"Apply a team-level cheating penalty (rating dock)","tags":["Ladders"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"points":{"type":"integer","minimum":1,"maximum":9007199254740991},"reason":{"type":"string","minLength":1,"maxLength":2000},"deactivate":{"type":"boolean"}},"required":["points","reason"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"before":{"type":"number"},"after":{"type":"number"},"delta":{"type":"number"},"deactivated":{"type":"boolean"}},"required":["before","after","delta","deactivated"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/presence/heartbeat":{"post":{"summary":"Record a presence heartbeat for a person","tags":["Presence"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sanityPersonId":{"type":"string","minLength":1,"maxLength":200},"context":{"type":"string","minLength":1,"maxLength":50}},"required":["sanityPersonId"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/presence":{"get":{"summary":"Read last-seen timestamps for a set of person ids","tags":["Presence"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"personIds","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"sanityPersonId":{"type":"string"},"context":{"nullable":true,"type":"string"},"lastSeenAt":{"type":"string","format":"date-time"}},"required":["sanityPersonId","context","lastSeenAt"],"additionalProperties":false}}},"required":["entries"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-templates":{"post":{"summary":"Create a weekly recurring slot template (forward-only)","tags":["Slots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"gameSlug":{"type":"string","minLength":1},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":15,"maximum":1440},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":0,"maximum":64},"timezone":{"type":"string"},"effectiveFrom":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["gameSlug","dayOfWeek","startTime"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"timezone":{"type":"string"},"effectiveFrom":{"type":"string"},"effectiveUntil":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","dayOfWeek","startTime","durationMinutes","kind","capacity","timezone","effectiveFrom","effectiveUntil","createdAt","updatedAt"],"additionalProperties":false}},"required":["template"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}},"get":{"summary":"List slot templates for a game","tags":["Slots"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"gameSlug","required":true},{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"includeClosed","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"timezone":{"type":"string"},"effectiveFrom":{"type":"string"},"effectiveUntil":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","dayOfWeek","startTime","durationMinutes","kind","capacity","timezone","effectiveFrom","effectiveUntil","createdAt","updatedAt"],"additionalProperties":false}}},"required":["templates"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-templates/{id}":{"patch":{"summary":"Edit a template forward-only (closes it and inserts a replacement)","tags":["Slots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":15,"maximum":1440},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":0,"maximum":64},"timezone":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"timezone":{"type":"string"},"effectiveFrom":{"type":"string"},"effectiveUntil":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","dayOfWeek","startTime","durationMinutes","kind","capacity","timezone","effectiveFrom","effectiveUntil","createdAt","updatedAt"],"additionalProperties":false}},"required":["template"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-templates/{id}/close":{"post":{"summary":"Close a template from a date (future unbooked instances are pruned)","tags":["Slots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"gameId":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"dayOfWeek":{"type":"integer","minimum":1,"maximum":7},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"timezone":{"type":"string"},"effectiveFrom":{"type":"string"},"effectiveUntil":{"nullable":true,"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","gameId","dayOfWeek","startTime","durationMinutes","kind","capacity","timezone","effectiveFrom","effectiveUntil","createdAt","updatedAt"],"additionalProperties":false}},"required":["template"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slots":{"get":{"summary":"Upcoming slot instances with availability (materializes lazily)","tags":["Slots"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"gameSlug","required":true},{"schema":{},"in":"query","name":"from","required":false},{"schema":{},"in":"query","name":"to","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"slots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"templateId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["open","reserve"]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["open","closed"]},"reservedRivals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reservedTournament":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"availableForRivals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","templateId","startsAt","endsAt","kind","capacity","status","reservedRivals","reservedTournament","availableForRivals"],"additionalProperties":false}}},"required":["slots"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slots/{id}/reservations":{"post":{"summary":"Reserve a slot (tournament bookings take priority and may overbook)","tags":["Slots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["rivals","tournament"]},"challengeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"divisionId":{"type":"string"},"roundId":{"type":"string"},"externalMatchId":{"type":"string"},"holdExpiresAt":{}},"required":["kind"]}}}},"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"instanceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["rivals","tournament"]},"status":{"type":"string","enum":["held","confirmed","cancelled","preempted"]},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"externalMatchId":{"nullable":true,"type":"string"},"holdExpiresAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","instanceId","kind","status","challengeId","ladderMatchId","tournamentSanityId","divisionId","roundId","externalMatchId","holdExpiresAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["reservation"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-reservations/{id}/confirm":{"post":{"summary":"Confirm a held reservation","tags":["Slots"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"instanceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["rivals","tournament"]},"status":{"type":"string","enum":["held","confirmed","cancelled","preempted"]},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"externalMatchId":{"nullable":true,"type":"string"},"holdExpiresAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","instanceId","kind","status","challengeId","ladderMatchId","tournamentSanityId","divisionId","roundId","externalMatchId","holdExpiresAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["reservation"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-reservations/{id}/release":{"post":{"summary":"Release a held or confirmed reservation","tags":["Slots"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"instanceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["rivals","tournament"]},"status":{"type":"string","enum":["held","confirmed","cancelled","preempted"]},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"externalMatchId":{"nullable":true,"type":"string"},"holdExpiresAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","instanceId","kind","status","challengeId","ladderMatchId","tournamentSanityId","divisionId","roundId","externalMatchId","holdExpiresAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["reservation"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/slot-reservations/{id}/preempt":{"post":{"summary":"Preempt a rivals reservation (tournament priority, fase 4)","tags":["Slots"],"parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"instanceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["rivals","tournament"]},"status":{"type":"string","enum":["held","confirmed","cancelled","preempted"]},"challengeId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ladderMatchId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"nullable":true,"type":"string"},"divisionId":{"nullable":true,"type":"string"},"roundId":{"nullable":true,"type":"string"},"externalMatchId":{"nullable":true,"type":"string"},"holdExpiresAt":{"nullable":true,"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","instanceId","kind","status","challengeId","ladderMatchId","tournamentSanityId","divisionId","roundId","externalMatchId","holdExpiresAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["reservation"],"additionalProperties":false}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tournaments/{sanityId}/live":{"get":{"summary":"Get the live provisional scoreboard for a tournament scope","tags":["Live"],"description":"Returns the active live-match-state-v1 snapshot for a tournament (optionally narrowed by divisionId / bracketId), or source \"none\" when no operator is live. Consumed server-side by Caster Studio, which polls it for the live overlay and falls back to standings when none.","parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"divisionId","required":false},{"schema":{"type":"string","minLength":1},"in":"query","name":"bracketId","required":false},{"schema":{"type":"string"},"in":"path","name":"sanityId","required":true,"description":"Sanity document id of the tournament"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","enum":["live","none"]},"session":{"nullable":true,"type":"object","properties":{"sessionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"type":"string"},"roundId":{"nullable":true,"type":"string"},"structureMatchId":{"type":"string"},"gameNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxGames":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","ended"]},"lastSequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updatedAt":{"type":"string"}},"required":["sessionId","tournamentSanityId","bracketId","divisionId","roundId","structureMatchId","gameNumber","maxGames","status","lastSequence","updatedAt"],"additionalProperties":false},"snapshot":{"nullable":true,"type":"object","additionalProperties":{}}},"required":["source","session","snapshot"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/live/sessions/{sessionId}":{"get":{"summary":"Get live session status","tags":["Live"],"description":"Returns the lifecycle/sequence status of a live session for studio diagnostics.","parameters":[{"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"in":"path","name":"sessionId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tournamentSanityId":{"type":"string"},"bracketId":{"nullable":true,"type":"string"},"divisionId":{"type":"string"},"roundId":{"nullable":true,"type":"string"},"structureMatchId":{"type":"string"},"gameNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxGames":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","ended"]},"lastSequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updatedAt":{"type":"string"}},"required":["sessionId","tournamentSanityId","bracketId","divisionId","roundId","structureMatchId","gameNumber","maxGames","status","lastSequence","updatedAt"],"additionalProperties":false}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{}}},"required":["error"],"additionalProperties":false}}}}}}}},"tags":[{"name":"Health","description":"Service health checks"},{"name":"Webhooks","description":"Signed result ingestion from external sources"},{"name":"Tournaments","description":"Tournament matches and leaderboards"},{"name":"Games","description":"Cross-tournament leaderboards per game"},{"name":"Matches","description":"Individual match lookups"},{"name":"Ladders","description":"Arena Rivals team ladders (enrollment, leaderboard)"},{"name":"Football","description":"EA FC head-to-head matches, results, and league tables"},{"name":"Presence","description":"Lightweight presence heartbeat (friends v1)"},{"name":"Slots","description":"Play-window slot templates, instances, and reservations"},{"name":"Live","description":"Provisional live scoreboard relay (certified operator ingest + overlay read)"}]}