Files
mixmaker/openapi/openapi.yaml
lemintare fa4edc0df5
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled
Add player profiles and community settings
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-19 21:43:48 +03:00

1467 lines
46 KiB
YAML

openapi: 3.1.0
info:
title: Mixmaker API
version: 0.1.0
description: API for Overwatch community scrims.
servers:
- url: /
security:
- cookieAuth: []
tags:
- name: Auth
- name: Players
- name: Community
- name: Events
- name: Teams
- name: Series
- name: Tournaments
paths:
/healthz:
get:
security: []
operationId: health
responses:
"200":
description: Healthy
/readyz:
get:
security: []
operationId: ready
responses:
"200":
description: Ready
"503":
description: Not ready
/api/auth/discord:
get:
security: []
tags: [Auth]
operationId: startDiscordLogin
responses:
"302":
description: Redirect to Discord
/api/auth/discord/callback:
get:
security: []
tags: [Auth]
operationId: finishDiscordLogin
parameters:
- name: code
in: query
required: true
schema:
type: string
- name: state
in: query
required: true
schema:
type: string
responses:
"302":
description: Session created
/api/auth/me:
get:
tags: [Auth]
operationId: getCurrentAccount
responses:
"200":
description: Current account
content:
application/json:
schema:
$ref: "#/components/schemas/Session"
"401":
$ref: "#/components/responses/Unauthorized"
/api/auth/logout:
post:
tags: [Auth]
operationId: logout
responses:
"204":
description: Logged out
/api/me/player:
patch:
tags: [Players]
operationId: updateMyPlayer
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerUpdate"
responses:
"200":
description: Updated profile
content:
application/json:
schema:
$ref: "#/components/schemas/Player"
"422":
$ref: "#/components/responses/ValidationError"
/api/players:
get:
tags: [Players]
operationId: listPlayers
responses:
"200":
description: Players
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Player"
/api/players/{playerId}:
get:
tags: [Players]
operationId: getPlayerProfile
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Public-safe player profile, aggregate statistics, and recent completed matches
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerProfile"
"404":
$ref: "#/components/responses/NotFound"
/api/community/settings:
get:
tags: [Community]
operationId: getCommunitySettings
responses:
"200":
description: Community settings
content:
application/json:
schema:
$ref: "#/components/schemas/CommunitySettings"
put:
tags: [Community]
operationId: updateCommunitySettings
description: Admin only. Moderators are forbidden.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [discordInviteUrl]
properties:
discordInviteUrl:
type: string
description: Empty, or an official discord.gg / discord.com/invite HTTPS URL.
responses:
"200":
description: Updated community settings
content:
application/json:
schema:
$ref: "#/components/schemas/CommunitySettings"
"403":
$ref: "#/components/responses/Forbidden"
/api/accounts:
get:
tags: [Admin]
operationId: listAccounts
responses:
"200":
description: Accounts visible to administrators
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/Account" }
"403": { $ref: "#/components/responses/Forbidden" }
/api/accounts/{accountId}/moderator:
patch:
tags: [Admin]
operationId: setModerator
parameters:
- name: accountId
in: path
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [moderator]
properties:
moderator: { type: boolean }
responses:
"200": { description: Updated account, content: { application/json: { schema: { $ref: "#/components/schemas/Account" } } } }
"403": { $ref: "#/components/responses/Forbidden" }
/api/events:
get:
tags: [Events]
operationId: listEvents
parameters:
- name: from
in: query
schema:
type: string
format: date-time
responses:
"200":
description: Events
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Event"
post:
tags: [Events]
operationId: createEvent
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EventCreateInput"
responses:
"201":
description: Event created
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
"403":
$ref: "#/components/responses/Forbidden"
/api/events/{eventId}:
get:
tags: [Events]
operationId: getEvent
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200":
description: Event details
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
"404":
$ref: "#/components/responses/NotFound"
put:
tags: [Events]
operationId: updateEvent
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EventInput"
responses:
"200":
description: Event updated
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
delete:
tags: [Events]
operationId: deleteEvent
description: Permanently removes the event and all event-scoped data.
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"204": { description: Event deleted }
"403": { $ref: "#/components/responses/Forbidden" }
"404": { $ref: "#/components/responses/NotFound" }
/api/events/{eventId}/cancel:
post:
tags: [Events]
operationId: cancelEvent
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200": { description: Event cancelled, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/tournament:
get:
tags: [Tournaments]
operationId: getEventTournament
description: Returns the tournament bracket hydrated with the latest state of every persisted series.
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200": { description: Live tournament bracket, content: { application/json: { schema: { $ref: "#/components/schemas/Tournament" } } } }
"404": { $ref: "#/components/responses/NotFound" }
/api/events/{eventId}/bracket-draft:
get:
tags: [Tournaments]
operationId: getBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
responses:
"200": { description: Editable bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
put:
tags: [Tournaments]
operationId: updateBracketDraft
description: Saves a structurally valid work-in-progress graph; slots and final layout may remain incomplete until confirmation.
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/BracketUpdateCommand" } } }
responses:
"200": { description: Updated graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/bracket-draft/initialize:
post:
tags: [Tournaments]
operationId: initializeBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"201": { description: Default bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/bracket-draft/reset:
post:
tags: [Tournaments]
operationId: resetBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"200": { description: Reset bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/bracket-draft/confirm:
post:
tags: [Tournaments]
operationId: confirmBracketDraft
description: Validates the complete graph, including filled slots and exactly one final match, then marks it confirmed.
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"200": { description: Confirmed bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/rsvps:
get:
tags: [Events]
operationId: listRegistrations
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200":
description: Registrations
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/EventRegistration"
/api/events/{eventId}/participants:
post:
tags: [Events]
operationId: createGuestParticipant
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [displayName, ratings, status]
properties:
displayName:
type: string
minLength: 1
ratings:
$ref: "#/components/schemas/Ratings"
status:
type: string
enum: [Going, Maybe, NotGoing]
responses:
"201":
description: Guest participant created and registered
content:
application/json:
schema:
type: object
required: [player, rsvp]
properties:
player:
$ref: "#/components/schemas/Player"
rsvp:
$ref: "#/components/schemas/EventRegistration"
"403":
$ref: "#/components/responses/Forbidden"
/api/events/{eventId}/rsvps/{playerId}:
put:
tags: [Events]
operationId: adminSetRegistration
parameters:
- $ref: "#/components/parameters/EventId"
- $ref: "#/components/parameters/PlayerId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegistrationInput"
responses:
"200":
description: Registration updated by admin
content:
application/json:
schema:
$ref: "#/components/schemas/EventRegistration"
"403":
$ref: "#/components/responses/Forbidden"
delete:
tags: [Events]
operationId: removeParticipantFromEvent
parameters:
- $ref: "#/components/parameters/EventId"
- $ref: "#/components/parameters/PlayerId"
responses:
"204":
description: Participant removed from the event
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
/api/events/{eventId}/balance:
post:
tags: [Teams]
operationId: generateBalanceCandidates
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
seed:
type: integer
format: int64
responses:
"200":
description: Three best candidates
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/BalanceCandidate"
/api/events/{eventId}/registration/close:
post:
tags: [Events]
operationId: closeRegistration
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CloseRegistrationCommand"
responses:
"200": { description: Registration closed, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/workflow/back:
post:
tags: [Events]
operationId: revertEventWorkflowStage
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200": { description: Workflow moved back one stage, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/balance/generate:
post:
tags: [Teams]
operationId: generateWorkflowBalance
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200":
description: Event and generated candidates
content:
application/json:
schema:
type: object
required: [event, candidates]
properties:
event: { $ref: "#/components/schemas/Event" }
candidates: { type: array, items: { $ref: "#/components/schemas/BalanceCandidate" } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster:
get:
tags: [Teams]
operationId: getRosterDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
responses:
"200": { description: Roster draft, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
put:
tags: [Teams]
operationId: selectWorkflowBalance
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [candidate, expectedVersion]
properties:
candidate: { $ref: "#/components/schemas/BalanceCandidate" }
expectedVersion: { type: integer }
responses:
"200": { description: Roster draft created, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster/swap:
post:
tags: [Teams]
operationId: swapRosterPlayers
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSwapCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster/move:
post:
tags: [Teams]
operationId: moveRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterMoveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/place-reserve:
post:
tags: [Teams]
operationId: placeReserveRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterPlaceReserveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/remove:
post:
tags: [Teams]
operationId: removeRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterRemoveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/substitute:
post:
tags: [Teams]
operationId: substituteRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSubstitutionCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/emergency-substitute:
post:
tags: [Teams]
operationId: emergencySubstituteRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSubstitutionCommand" } } }
responses:
"200": { description: Updated live roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/captain:
put:
tags: [Teams]
operationId: setRosterCaptain
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, playerId, expectedVersion]
properties:
teamId: { type: string }
playerId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/confirm:
post:
tags: [Teams]
operationId: confirmRosters
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedVersion, expectedRosterVersion]
properties:
expectedVersion: { type: integer }
expectedRosterVersion: { type: integer }
responses:
"200": { description: Rosters confirmed, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
/api/events/{eventId}/start:
post:
tags: [Events]
operationId: startScrim
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"201":
description: Scrim started
content:
application/json:
schema:
type: object
required: [event]
properties:
event: { $ref: "#/components/schemas/Event" }
series: { $ref: "#/components/schemas/Series" }
tournament: { $ref: "#/components/schemas/Tournament" }
/api/teams/{teamId}/captain:
put:
tags: [Teams]
operationId: assignCaptain
parameters:
- $ref: "#/components/parameters/TeamId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [playerId]
properties:
playerId:
type: string
format: uuid
responses:
"200":
description: Captain assigned
content:
application/json:
schema:
$ref: "#/components/schemas/Team"
"422":
$ref: "#/components/responses/ValidationError"
/api/teams/{teamId}/name:
put:
tags: [Teams]
operationId: renameLiveTeam
parameters:
- $ref: "#/components/parameters/TeamId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string, minLength: 2, maxLength: 32 }
responses:
"200": { description: Team renamed, content: { application/json: { schema: { $ref: "#/components/schemas/Team" } } } }
"403": { $ref: "#/components/responses/Forbidden" }
"409": { $ref: "#/components/responses/Conflict" }
/api/coin-toss:
post:
tags: [Series]
operationId: tossCoin
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamAId, teamBId, seed, eventId, actingTeamId]
properties:
teamAId: { type: string }
teamBId: { type: string }
seed: { type: string }
eventId: { type: string }
actingTeamId: { type: string }
responses:
"200":
description: Coin toss result
content:
application/json:
schema:
type: object
/api/drafts/{seriesId}/map-bans:
post:
tags: [Series]
operationId: banMap
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, map, eventId, version]
properties:
teamId: { type: string }
map: { type: string }
eventId: { type: string }
version:
type: integer
responses:
"200":
description: Updated series
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
"409":
$ref: "#/components/responses/Conflict"
/api/drafts/{seriesId}/hero-bans:
post:
tags: [Series]
operationId: banHero
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, hero, eventId, version]
properties:
teamId: { type: string }
hero: { type: string }
eventId: { type: string }
version:
type: integer
responses:
"200":
description: Updated series
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
"409":
$ref: "#/components/responses/Conflict"
/api/series/{seriesId}:
get:
tags: [Series]
operationId: getSeries
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
responses:
"200": { description: Full live series state, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
/api/series/{seriesId}/coin-toss:
post:
tags: [Series]
operationId: tossSeriesCoin
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [seed, actingTeamId, expectedVersion]
properties:
seed: { type: string }
actingTeamId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-bans:
post:
tags: [Series]
operationId: banSeriesMap
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-pick:
post:
tags: [Series]
operationId: pickSeriesMap
description: The previous map loser picks the next map directly.
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series with hero bans started, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/hero-bans:
post:
tags: [Series]
operationId: banSeriesHero
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-result:
post:
tags: [Series]
operationId: recordSeriesMapResult
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [outcome, actingTeamId, expectedVersion]
properties:
outcome: { type: string, enum: [TeamAWin, TeamBWin, Draw] }
actingTeamId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
/api/series/{seriesId}/results:
post:
tags: [Series]
operationId: recordMapResult
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MapResultInput"
responses:
"200":
description: Result recorded
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
/api/events/stream:
get:
tags: [Series]
operationId: subscribeSeries
parameters:
- name: topic
in: query
schema:
type: string
responses:
"200":
description: Server-sent event stream
content:
text/event-stream:
schema:
type: string
/api/tournaments/{tournamentId}:
get:
tags: [Tournaments]
operationId: getTournament
parameters:
- $ref: "#/components/parameters/TournamentId"
responses:
"200":
description: Tournament bracket
content:
application/json:
schema:
$ref: "#/components/schemas/Tournament"
components:
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: mixmaker_session
parameters:
EventId:
name: eventId
in: path
required: true
schema:
type: string
format: uuid
PlayerId:
name: playerId
in: path
required: true
schema:
type: string
format: uuid
TeamId:
name: teamId
in: path
required: true
schema:
type: string
format: uuid
SeriesId:
name: seriesId
in: path
required: true
schema:
type: string
format: uuid
TournamentId:
name: tournamentId
in: path
required: true
schema:
type: string
format: uuid
responses:
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
Forbidden:
description: Insufficient permission
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
Conflict:
description: State version conflict
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
ValidationError:
description: Invalid command
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
schemas:
Session:
type: object
required: [account, player]
properties:
account:
$ref: "#/components/schemas/Account"
player:
$ref: "#/components/schemas/Player"
Account:
type: object
required: [id, discordId, username, role, createdAt]
properties:
id:
type: string
format: uuid
discordId:
type: string
username:
type: string
avatarUrl:
type: [string, "null"]
format: uri
role:
type: string
enum: [player, moderator, admin]
createdAt:
type: string
format: date-time
Ratings:
type: object
required: [tank, damage, support]
properties:
tank:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
damage:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
support:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
Player:
type: object
required: [id, accountId, displayName, battleTag, ratings, preferredRoles, preferredPlayerIds, avoidedPlayerIds, updatedAt]
properties:
id:
type: string
format: uuid
accountId:
type: string
format: uuid
displayName:
type: string
minLength: 2
maxLength: 32
battleTag:
type: string
pattern: '^(|[^#\s]{2,20}#[0-9]{3,12})$'
description: Optional; an empty string clears the BattleTag.
ratings:
$ref: "#/components/schemas/Ratings"
preferredRoles:
type: array
items:
type: string
enum: [Tank, Damage, Support]
preferredPlayerIds:
type: array
maxItems: 3
items:
type: string
avoidedPlayerIds:
type: array
maxItems: 3
description: Soft preference to place these players on another team.
items:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
PlayerUpdate:
type: object
required: [ratings]
properties:
displayName:
type: string
minLength: 2
maxLength: 32
battleTag:
type: string
description: Empty string clears the BattleTag.
ratings:
$ref: "#/components/schemas/Ratings"
preferredRoles:
type: array
items:
type: string
enum: [Tank, Damage, Support]
preferredPlayerIds:
type: array
maxItems: 3
items:
type: string
avoidedPlayerIds:
type: array
maxItems: 3
items:
type: string
PublicPlayer:
type: object
required: [id, displayName, battleTag, ratings, isGuest]
properties:
id: { type: string }
displayName: { type: string, minLength: 2, maxLength: 32 }
battleTag: { type: string }
ratings: { $ref: "#/components/schemas/Ratings" }
isGuest: { type: boolean }
PlayerStatsSummary:
type: object
required: [seriesPlayed, seriesWon, seriesLost, winRate, mapsPlayed, mapsWon, mapsLost, mapsDrawn]
properties:
seriesPlayed: { type: integer }
seriesWon: { type: integer }
seriesLost: { type: integer }
winRate: { type: number, minimum: 0, maximum: 1 }
mapsPlayed: { type: integer }
mapsWon: { type: integer }
mapsLost: { type: integer }
mapsDrawn: { type: integer }
PlayerMatchHistory:
type: object
required: [seriesId, eventId, eventName, eventDate, ownTeamId, ownTeamName, opponentTeamId, opponentTeamName, ownScore, opponentScore, outcome]
properties:
seriesId: { type: string }
eventId: { type: string }
eventName: { type: string }
eventDate: { type: string, format: date-time }
ownTeamId: { type: string }
ownTeamName: { type: string }
opponentTeamId: { type: string }
opponentTeamName: { type: string }
ownScore: { type: integer }
opponentScore: { type: integer }
outcome: { type: string, enum: [win, loss] }
PlayerProfile:
type: object
required: [player, summary, recentMatches]
properties:
player: { $ref: "#/components/schemas/PublicPlayer" }
summary: { $ref: "#/components/schemas/PlayerStatsSummary" }
recentMatches:
type: array
items: { $ref: "#/components/schemas/PlayerMatchHistory" }
CommunitySettings:
type: object
required: [discordInviteUrl, updatedAt, updatedBy]
properties:
discordInviteUrl: { type: string }
updatedAt: { type: string, format: date-time }
updatedBy: { type: string }
EventInput:
type: object
required: [name, startsAt, endsAt, registrationDeadline]
properties:
name:
type: string
minLength: 1
description:
type: string
startsAt:
type: string
format: date-time
endsAt:
type: string
format: date-time
registrationDeadline:
type: string
format: date-time
description: Synchronized by the server to startsAt.
EventCreateInput:
allOf:
- $ref: "#/components/schemas/EventInput"
- type: object
properties:
pingEveryone:
type: boolean
default: true
description: Whether the Discord announcement should notify @everyone. The announcement is still posted when false.
Event:
allOf:
- $ref: "#/components/schemas/EventInput"
- type: object
required: [id, createdBy, createdAt, updatedAt, state, version, rulesetId, activeSeriesId, tournamentId]
properties:
id:
type: string
format: uuid
createdBy:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
state:
type: string
enum: [RegistrationOpen, RegistrationClosed, Balancing, RostersDraft, RostersConfirmed, BracketDraft, Live, Completed, Cancelled]
version: { type: integer }
rulesetId: { type: string }
activeSeriesId: { type: string }
tournamentId: { type: string }
RegistrationInput:
type: object
required: [status]
properties:
status:
type: string
enum: [Going, Maybe, NotGoing]
EventRegistration:
type: object
required: [eventId, playerId, status, actorAccountId, source, updatedAt]
properties:
eventId:
type: string
format: uuid
playerId:
type: string
format: uuid
status:
type: string
enum: [Going, Maybe, NotGoing]
actorAccountId:
type: string
format: uuid
source:
type: string
enum: [player, admin]
updatedAt:
type: string
format: date-time
TeamSlot:
type: object
required: [playerId, role, rating]
properties:
playerId:
type: string
role:
type: string
enum: [Tank, Damage, Support]
rating:
type: integer
Team:
type: object
required: [id, eventId, name, captainPlayerId, slots]
properties:
id:
type: string
eventId:
type: string
name:
type: string
captainPlayerId:
type: string
slots:
type: array
minItems: 5
maxItems: 5
items:
$ref: "#/components/schemas/TeamSlot"
BalanceCandidate:
type: object
required: [score, teams, reserve]
properties:
score:
type: integer
teams:
type: array
items:
$ref: "#/components/schemas/Team"
reserve:
type: array
items:
type: string
VersionCommand:
type: object
required: [expectedVersion]
properties:
expectedVersion: { type: integer }
CloseRegistrationCommand:
type: object
required: [rulesetId, expectedVersion]
properties:
rulesetId: { type: string }
expectedVersion: { type: integer }
RosterDraft:
type: object
required: [eventId, teams, reserve, version, confirmed]
properties:
eventId: { type: string }
teams: { type: array, minItems: 2, items: { $ref: "#/components/schemas/Team" } }
reserve: { type: array, items: { type: string } }
version: { type: integer }
confirmed: { type: boolean }
RosterSwapCommand:
type: object
required: [teamAId, playerAId, teamBId, playerBId, expectedVersion]
properties:
teamAId: { type: string }
playerAId: { type: string }
teamBId: { type: string }
playerBId: { type: string }
expectedVersion: { type: integer }
RosterMoveCommand:
type: object
required: [fromTeamId, playerId, toTeamId, role, expectedVersion]
properties:
fromTeamId: { type: string }
playerId: { type: string }
toTeamId: { type: string }
role: { type: string, enum: [Tank, Damage, Support] }
expectedVersion: { type: integer }
RosterPlaceReserveCommand:
type: object
required: [teamId, reservePlayerId, role, expectedVersion]
properties:
teamId: { type: string }
reservePlayerId: { type: string }
role: { type: string, enum: [Tank, Damage, Support] }
expectedVersion: { type: integer }
RosterRemoveCommand:
type: object
required: [teamId, playerId, expectedVersion]
properties:
teamId: { type: string }
playerId: { type: string }
expectedVersion: { type: integer }
RosterSubstitutionCommand:
type: object
required: [teamId, outgoingPlayerId, reservePlayerId, expectedVersion]
properties:
teamId: { type: string }
outgoingPlayerId: { type: string }
reservePlayerId: { type: string }
expectedVersion: { type: integer }
SeriesBanCommand:
type: object
required: [teamId, expectedVersion]
properties:
teamId: { type: string }
map: { type: string }
hero: { type: string }
expectedVersion: { type: integer }
MapResultInput:
type: object
required: [mapName, outcome, expectedVersion]
properties:
mapName:
type: string
outcome:
type: string
enum: [TeamAWin, TeamBWin, Draw]
expectedVersion:
type: integer
Series:
type: object
required: [id, eventId, tournamentId, teamAId, teamBId, winnerTeamId, bestOf, rulesetId, phase, playedMaps, seriesBans, maps, audit, results, version]
properties:
id:
type: string
eventId:
type: string
tournamentId:
type: string
teamAId:
type: string
teamBId:
type: string
winnerTeamId:
type: string
bestOf:
type: integer
rulesetId: { type: string }
phase:
type: string
enum: [CoinTossPending, MapBan, MapPick, HeroBan, Playing, Completed]
coinToss: { type: [object, "null"] }
mapDraft: { type: [object, "null"] }
heroDraft: { type: [object, "null"] }
currentMap: { type: string }
playedMaps: { type: array, items: { type: string } }
nextMapPickerId: { type: string }
availableMaps: { type: array, items: { type: string } }
seriesBans:
type: object
additionalProperties:
type: array
items: { type: string }
maps:
type: array
items:
type: object
required: [number, name, heroBans]
properties:
number: { type: integer }
name: { type: string }
heroBans:
type: array
items:
type: object
required: [teamId, value, actorAccountId, at]
properties:
teamId: { type: string }
value: { type: string }
actorAccountId: { type: string }
at: { type: string, format: date-time }
result: { type: [object, "null"] }
audit: { type: array, items: { type: object } }
results:
type: array
items:
type: object
version:
type: integer
BracketSlotSource:
type: object
required: [kind]
properties:
kind: { type: string, enum: [Team, Winner, Loser] }
teamId: { type: string }
matchId: { type: string }
BracketMatch:
type: object
required: [id, round, order, slotA, slotB]
properties:
id: { type: string }
round: { type: integer, minimum: 0 }
order: { type: integer, minimum: 0 }
slotA: { $ref: "#/components/schemas/BracketSlotSource" }
slotB: { $ref: "#/components/schemas/BracketSlotSource" }
seriesId: { type: string }
teamAId: { type: string }
teamBId: { type: string }
winnerTeamId: { type: string }
series: { $ref: "#/components/schemas/Series" }
BracketDraft:
type: object
required: [eventId, teamIds, matches, version, confirmed]
properties:
eventId: { type: string }
teamIds: { type: array, items: { type: string } }
matches: { type: array, items: { $ref: "#/components/schemas/BracketMatch" } }
version: { type: integer }
confirmed: { type: boolean }
BracketUpdateCommand:
type: object
required: [matches, expectedVersion]
properties:
matches: { type: array, items: { $ref: "#/components/schemas/BracketMatch" } }
expectedVersion: { type: integer }
Tournament:
type: object
required: [id, eventId, name, winnerTeamId, teamIds, matches, rounds, version]
properties:
id:
type: string
eventId:
type: string
name:
type: string
winnerTeamId:
type: string
teamIds:
type: array
items:
type: string
matches:
type: array
items:
$ref: "#/components/schemas/BracketMatch"
rounds:
type: array
items:
type: array
items:
$ref: "#/components/schemas/Series"
version: { type: integer }
Problem:
type: object
required: [error]
properties:
error:
type: string