3627 lines
108 KiB
YAML
3627 lines
108 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Galaxy Backend REST API
|
|
version: v1
|
|
description: |
|
|
This specification documents the consolidated `galaxy/backend` REST surface
|
|
consumed by `gateway` over the trusted internal network. It covers five
|
|
route families:
|
|
|
|
- `/api/v1/public/*` — unauthenticated public endpoints (only auth in MVP);
|
|
- `/healthz`, `/readyz` — unauthenticated infrastructure probes;
|
|
- `/api/v1/user/*` — authenticated end-user endpoints; the trusted
|
|
`X-User-ID` header injected by gateway is the sole identity input;
|
|
- `/api/v1/admin/*` — administrative endpoints gated by HTTP Basic Auth
|
|
against the `admin_accounts` table;
|
|
- `/api/v1/internal/*` — gateway-only server-to-server endpoints; trusted
|
|
as part of the user surface in MVP (no extra auth).
|
|
|
|
Every endpoint emits a JSON envelope of the shape
|
|
`{"error":{"code":"...","message":"..."}}` on failure. The closed set of
|
|
`code` values is enumerated under `components.schemas.ErrorBody`. JSON
|
|
field names use `snake_case` everywhere on the wire.
|
|
servers:
|
|
- url: http://backend.internal
|
|
description: |
|
|
Backend internal listener reachable only from gateway. The actual
|
|
address is configured by `BACKEND_HTTP_LISTEN_ADDR`.
|
|
tags:
|
|
- name: Public
|
|
description: Unauthenticated public endpoints (registration and login).
|
|
- name: Probes
|
|
description: Liveness and readiness probes used by infrastructure tooling.
|
|
- name: User
|
|
description: Authenticated end-user endpoints; the trusted `X-User-ID` header carries identity.
|
|
- name: Admin
|
|
description: Administrator endpoints gated by HTTP Basic Auth.
|
|
- name: Internal
|
|
description: Gateway-only server-to-server endpoints used to lookup and revoke device sessions.
|
|
paths:
|
|
/healthz:
|
|
get:
|
|
tags: [Probes]
|
|
operationId: getHealthz
|
|
summary: Liveness probe
|
|
description: Returns `200` for as long as the process is alive.
|
|
security: []
|
|
responses:
|
|
"200":
|
|
description: Process is alive.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/HealthzResponse"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/readyz:
|
|
get:
|
|
tags: [Probes]
|
|
operationId: getReadyz
|
|
summary: Readiness probe
|
|
description: |
|
|
Returns `200` once the Postgres pool is open, embedded migrations are
|
|
applied, and the gRPC push listener is bound. Returns `503` until all
|
|
of those hold.
|
|
security: []
|
|
responses:
|
|
"200":
|
|
description: Process is ready to serve traffic.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ReadyzResponse"
|
|
"503":
|
|
$ref: "#/components/responses/ServiceUnavailableError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/public/auth/send-email-code:
|
|
post:
|
|
tags: [Public]
|
|
operationId: publicAuthSendEmailCode
|
|
summary: Issue an e-mail login challenge
|
|
description: |
|
|
Requests a six-digit login code be e-mailed to the supplied address.
|
|
Returns the same opaque `challenge_id` shape regardless of whether the
|
|
target account exists, so callers cannot use this endpoint to enumerate
|
|
user accounts. Permanently blocked addresses are rejected with `400`.
|
|
security: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/AcceptLanguage"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PublicAuthSendEmailCodeRequest"
|
|
responses:
|
|
"200":
|
|
description: Challenge accepted; an e-mail will be delivered out-of-band.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PublicAuthSendEmailCodeResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/public/auth/confirm-email-code:
|
|
post:
|
|
tags: [Public]
|
|
operationId: publicAuthConfirmEmailCode
|
|
summary: Confirm an e-mail login challenge
|
|
description: |
|
|
Confirms a previously issued `challenge_id` by submitting the delivered
|
|
verification `code` together with the client's Ed25519 public key and
|
|
IANA time zone. On success the backend creates a device session and
|
|
returns its identifier.
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PublicAuthConfirmEmailCodeRequest"
|
|
responses:
|
|
"200":
|
|
description: Device session created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PublicAuthConfirmEmailCodeResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/account:
|
|
get:
|
|
tags: [User]
|
|
operationId: userAccountGet
|
|
summary: Get the current user account aggregate
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Current account aggregate.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/account/profile:
|
|
patch:
|
|
tags: [User]
|
|
operationId: userAccountUpdateProfile
|
|
summary: Update the caller's mutable profile fields
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpdateProfileRequest"
|
|
responses:
|
|
"200":
|
|
description: Updated account aggregate.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/account/settings:
|
|
patch:
|
|
tags: [User]
|
|
operationId: userAccountUpdateSettings
|
|
summary: Update the caller's settings fields
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpdateSettingsRequest"
|
|
responses:
|
|
"200":
|
|
description: Updated account aggregate.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/account/delete:
|
|
post:
|
|
tags: [User]
|
|
operationId: userAccountDelete
|
|
summary: Soft-delete the caller's account
|
|
description: |
|
|
Marks the caller's account `deleted_at` and triggers the documented
|
|
in-process cascade across lobby, notification, and geo modules.
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"204":
|
|
description: Account scheduled for soft delete.
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyGamesList
|
|
summary: List public lobby games with paging
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of public games.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GameSummaryPage"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesCreate
|
|
summary: Create a new private lobby game owned by the caller
|
|
description: |
|
|
Always emits a `private` game owned by `X-User-ID`. Public games
|
|
are created via `POST /api/v1/admin/games`.
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameCreateRequest"
|
|
responses:
|
|
"201":
|
|
description: Game created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyGamesGet
|
|
summary: Get the lobby game detail
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Lobby game detail.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
patch:
|
|
tags: [User]
|
|
operationId: userLobbyGamesUpdate
|
|
summary: Update mutable lobby game fields (owner only)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameUpdateRequest"
|
|
responses:
|
|
"200":
|
|
description: Updated lobby game detail.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/open-enrollment:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesOpenEnrollment
|
|
summary: Move a draft game into `enrollment_open`
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Enrollment opened.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/ready-to-start:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesReadyToStart
|
|
summary: Mark a game `ready_to_start`
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Game transitioned to `ready_to_start`.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/start:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesStart
|
|
summary: Start the engine container for the game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"202":
|
|
description: Start request accepted; runtime job queued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/pause:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesPause
|
|
summary: Pause a running game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Game paused.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/resume:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesResume
|
|
summary: Resume a paused game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Game resumed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/cancel:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesCancel
|
|
summary: Cancel a game (owner)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Game cancelled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/retry-start:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyGamesRetryStart
|
|
summary: Retry a failed start
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"202":
|
|
description: Retry queued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/applications:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyApplicationsSubmit
|
|
summary: Submit an application to join a game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyApplicationSubmitRequest"
|
|
responses:
|
|
"201":
|
|
description: Application created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyApplicationDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/applications/{application_id}/approve:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyApplicationsApprove
|
|
summary: Approve an application (owner or admin)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/ApplicationID"
|
|
responses:
|
|
"200":
|
|
description: Application approved.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyApplicationDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/applications/{application_id}/reject:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyApplicationsReject
|
|
summary: Reject an application (owner or admin)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/ApplicationID"
|
|
responses:
|
|
"200":
|
|
description: Application rejected.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyApplicationDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/invites:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyInvitesIssue
|
|
summary: Issue an invite to join a private game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteIssueRequest"
|
|
responses:
|
|
"201":
|
|
description: Invite created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/invites/{invite_id}/redeem:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyInvitesRedeem
|
|
summary: Redeem an invite to create a membership
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/InviteID"
|
|
responses:
|
|
"200":
|
|
description: Invite redeemed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/invites/{invite_id}/decline:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyInvitesDecline
|
|
summary: Decline an invite (recipient)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/InviteID"
|
|
responses:
|
|
"200":
|
|
description: Invite declined.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/invites/{invite_id}/revoke:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyInvitesRevoke
|
|
summary: Revoke an invite (issuer)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/InviteID"
|
|
responses:
|
|
"200":
|
|
description: Invite revoked.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/memberships:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyMembershipsList
|
|
summary: List memberships for a game
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Memberships for the game.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyMembershipList"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/memberships/{membership_id}/remove:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyMembershipsRemove
|
|
summary: Remove a membership (owner or self)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/MembershipID"
|
|
responses:
|
|
"200":
|
|
description: Membership removed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyMembershipDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/games/{game_id}/memberships/{membership_id}/block:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyMembershipsBlock
|
|
summary: Block a membership (owner)
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/MembershipID"
|
|
responses:
|
|
"200":
|
|
description: Membership blocked.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyMembershipDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/ForbiddenError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/my/games:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyMyGames
|
|
summary: List games the caller participates in
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's games.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MyGamesListResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/my/applications:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyMyApplications
|
|
summary: List the caller's applications
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's applications.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyApplicationList"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/my/invites:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyMyInvites
|
|
summary: List the caller's invites
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's invites.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyInviteList"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/my/race-names:
|
|
get:
|
|
tags: [User]
|
|
operationId: userLobbyMyRaceNames
|
|
summary: List the caller's race names
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's race-name records.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RaceNameList"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/lobby/race-names/register:
|
|
post:
|
|
tags: [User]
|
|
operationId: userLobbyRaceNamesRegister
|
|
summary: Promote a `pending_registration` to `registered`
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RaceNameRegisterRequest"
|
|
responses:
|
|
"200":
|
|
description: Race name promoted.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RaceNameDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/games/{game_id}/commands:
|
|
post:
|
|
tags: [User]
|
|
operationId: userGamesCommands
|
|
summary: Forward an engine command batch
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineCommand"
|
|
responses:
|
|
"200":
|
|
description: Engine command result passed through.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PassthroughObject"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/games/{game_id}/orders:
|
|
post:
|
|
tags: [User]
|
|
operationId: userGamesOrders
|
|
summary: Forward an engine order batch
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineOrder"
|
|
responses:
|
|
"200":
|
|
description: Engine order validation result passed through.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PassthroughObject"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/games/{game_id}/reports/{turn}:
|
|
get:
|
|
tags: [User]
|
|
operationId: userGamesReport
|
|
summary: Read an engine turn report
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/GameID"
|
|
- $ref: "#/components/parameters/Turn"
|
|
responses:
|
|
"200":
|
|
description: Engine report passed through.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PassthroughObject"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/sessions:
|
|
get:
|
|
tags: [User]
|
|
operationId: userSessionsList
|
|
summary: List the caller's active device sessions
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's active device sessions.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserSessionList"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/sessions/revoke-all:
|
|
post:
|
|
tags: [User]
|
|
operationId: userSessionsRevokeAll
|
|
summary: Revoke every device session belonging to the caller
|
|
description: |
|
|
Logout from every device. Subsequent authenticated requests on
|
|
any of the caller's sessions are rejected. Each revocation is
|
|
recorded in `session_revocations` with `actor_kind=user_self`.
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
responses:
|
|
"200":
|
|
description: Caller's sessions revoked.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeviceSessionRevocationSummary"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/user/sessions/{device_session_id}/revoke:
|
|
post:
|
|
tags: [User]
|
|
operationId: userSessionsRevoke
|
|
summary: Revoke one of the caller's device sessions
|
|
description: |
|
|
Logout from a single device. The target `device_session_id`
|
|
must belong to the caller; otherwise the endpoint returns
|
|
`404 not_found` (the same shape as a missing session) so the
|
|
endpoint cannot be used to probe foreign session ids. The
|
|
revocation is recorded in `session_revocations` with
|
|
`actor_kind=user_self`.
|
|
security:
|
|
- UserHeader: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/XUserID"
|
|
- $ref: "#/components/parameters/DeviceSessionID"
|
|
responses:
|
|
"200":
|
|
description: Device session revoked.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeviceSession"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/admin-accounts:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsList
|
|
summary: List admin accounts
|
|
security:
|
|
- AdminBasicAuth: []
|
|
responses:
|
|
"200":
|
|
description: Admin accounts.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccountList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsCreate
|
|
summary: Create an admin account
|
|
security:
|
|
- AdminBasicAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccountCreateRequest"
|
|
responses:
|
|
"201":
|
|
description: Admin account created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/admin-accounts/{username}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsGet
|
|
summary: Get an admin account
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Username"
|
|
responses:
|
|
"200":
|
|
description: Admin account.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/admin-accounts/{username}/disable:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsDisable
|
|
summary: Disable an admin account
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Username"
|
|
responses:
|
|
"200":
|
|
description: Admin account disabled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/admin-accounts/{username}/enable:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsEnable
|
|
summary: Enable an admin account
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Username"
|
|
responses:
|
|
"200":
|
|
description: Admin account enabled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/admin-accounts/{username}/reset-password:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminAdminAccountsResetPassword
|
|
summary: Reset an admin account password
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Username"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccountResetPasswordRequest"
|
|
responses:
|
|
"200":
|
|
description: Password reset; the new value is delivered out-of-band.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminUsersList
|
|
summary: List users
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of users.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminUserList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users/{user_id}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminUsersGet
|
|
summary: Get a user account aggregate
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
responses:
|
|
"200":
|
|
description: Account aggregate.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users/{user_id}/sanctions:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminUsersAddSanction
|
|
summary: Apply a sanction to a user
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminUserSanctionRequest"
|
|
responses:
|
|
"200":
|
|
description: Sanction applied.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users/{user_id}/limits:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminUsersAddLimit
|
|
summary: Apply a per-user limit override
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminUserLimitRequest"
|
|
responses:
|
|
"200":
|
|
description: Limit applied.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users/{user_id}/entitlements:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminUsersAddEntitlement
|
|
summary: Update a user's entitlement
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminUserEntitlementRequest"
|
|
responses:
|
|
"200":
|
|
description: Entitlement updated.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/users/{user_id}/soft-delete:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminUsersSoftDelete
|
|
summary: Soft-delete a user (admin)
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
responses:
|
|
"204":
|
|
description: User scheduled for soft delete.
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/games:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminGamesList
|
|
summary: List games for administration
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of games.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminGameList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminGamesCreate
|
|
summary: Create a public lobby game (admin-only)
|
|
description: |
|
|
Creates a public game owned collectively by administrators
|
|
(`visibility=public`, `owner_user_id=NULL`). The user-facing
|
|
`POST /api/v1/user/lobby/games` only creates private games.
|
|
security:
|
|
- AdminBasicAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminGameCreateRequest"
|
|
responses:
|
|
"201":
|
|
description: Public game created.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/games/{game_id}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminGamesGet
|
|
summary: Get an admin-side game detail
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Game detail.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/games/{game_id}/force-start:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminGamesForceStart
|
|
summary: Force-start a game
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"202":
|
|
description: Force-start queued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/games/{game_id}/force-stop:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminGamesForceStop
|
|
summary: Force-stop a game
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Force-stop accepted.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyGameStateChange"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/games/{game_id}/ban-member:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminGamesBanMember
|
|
summary: Ban a member from a game
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AdminGameBanMemberRequest"
|
|
responses:
|
|
"200":
|
|
description: Member banned.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LobbyMembershipDetail"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/runtimes/{game_id}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminRuntimesGet
|
|
summary: Read the runtime record for a game
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: Runtime record.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RuntimeRecord"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/runtimes/{game_id}/restart:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminRuntimesRestart
|
|
summary: Restart the engine container for a game
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"202":
|
|
description: Restart queued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RuntimeOperation"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/runtimes/{game_id}/patch:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminRuntimesPatch
|
|
summary: Patch the engine version (semver-patch only)
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RuntimePatchRequest"
|
|
responses:
|
|
"202":
|
|
description: Patch queued.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RuntimeOperation"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/runtimes/{game_id}/force-next-turn:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminRuntimesForceNextTurn
|
|
summary: Schedule a one-shot extra turn tick
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/GameID"
|
|
responses:
|
|
"200":
|
|
description: One-shot tick scheduled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RuntimeOperation"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/engine-versions:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminEngineVersionsList
|
|
summary: List engine versions
|
|
security:
|
|
- AdminBasicAuth: []
|
|
responses:
|
|
"200":
|
|
description: Engine versions.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersionList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminEngineVersionsCreate
|
|
summary: Register a new engine version
|
|
security:
|
|
- AdminBasicAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersionCreateRequest"
|
|
responses:
|
|
"201":
|
|
description: Engine version registered.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersion"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/engine-versions/{id}:
|
|
patch:
|
|
tags: [Admin]
|
|
operationId: adminEngineVersionsUpdate
|
|
summary: Update an engine version record
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/EngineVersionID"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersionUpdateRequest"
|
|
responses:
|
|
"200":
|
|
description: Engine version updated.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersion"
|
|
"400":
|
|
$ref: "#/components/responses/InvalidRequestError"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/engine-versions/{id}/disable:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminEngineVersionsDisable
|
|
summary: Disable an engine version
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/EngineVersionID"
|
|
responses:
|
|
"200":
|
|
description: Engine version disabled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EngineVersion"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/mail/deliveries:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminMailListDeliveries
|
|
summary: List mail deliveries
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of mail deliveries.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MailDeliveryList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/mail/deliveries/{delivery_id}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminMailGetDelivery
|
|
summary: Get a mail delivery
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/DeliveryID"
|
|
responses:
|
|
"200":
|
|
description: Mail delivery.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MailDelivery"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/mail/deliveries/{delivery_id}/attempts:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminMailListDeliveryAttempts
|
|
summary: List mail delivery attempts
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/DeliveryID"
|
|
responses:
|
|
"200":
|
|
description: Mail delivery attempts.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MailAttemptList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/mail/deliveries/{delivery_id}/resend:
|
|
post:
|
|
tags: [Admin]
|
|
operationId: adminMailResendDelivery
|
|
summary: Resend a non-sent mail delivery
|
|
description: |
|
|
Re-arms a delivery for another attempt cycle. Allowed states are
|
|
`pending`, `retrying`, and `dead_lettered`. Resend on a `sent`
|
|
delivery returns `409 Conflict` to prevent operators from
|
|
accidentally dispatching a duplicate copy of an already-delivered
|
|
mail.
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/DeliveryID"
|
|
responses:
|
|
"202":
|
|
description: Resend scheduled.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MailDelivery"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/ConflictError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/mail/dead-letters:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminMailListDeadLetters
|
|
summary: List mail dead-letters
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of dead-letters.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/MailDeadLetterList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/notifications:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminNotificationsList
|
|
summary: List notifications
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of notifications.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/NotificationList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/notifications/{notification_id}:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminNotificationsGet
|
|
summary: Get a notification
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/NotificationID"
|
|
responses:
|
|
"200":
|
|
description: Notification.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/NotificationDetail"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/notifications/dead-letters:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminNotificationsListDeadLetters
|
|
summary: List notification dead-letters
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of notification dead-letters.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/NotificationDeadLetterList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/notifications/malformed:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminNotificationsListMalformed
|
|
summary: List malformed notification intents
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/Page"
|
|
- $ref: "#/components/parameters/PageSize"
|
|
responses:
|
|
"200":
|
|
description: Page of malformed intents.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/NotificationMalformedList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/admin/geo/users/{user_id}/countries:
|
|
get:
|
|
tags: [Admin]
|
|
operationId: adminGeoListUserCountries
|
|
summary: List per-country counters for a user
|
|
security:
|
|
- AdminBasicAuth: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
responses:
|
|
"200":
|
|
description: Per-country counters for the user.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/GeoCountryCounterList"
|
|
"401":
|
|
$ref: "#/components/responses/UnauthorizedError"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/internal/sessions/{device_session_id}:
|
|
get:
|
|
tags: [Internal]
|
|
operationId: internalSessionsGet
|
|
summary: Look up a device session (gateway-only)
|
|
security: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/DeviceSessionID"
|
|
responses:
|
|
"200":
|
|
description: Device session record.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DeviceSession"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
/api/v1/internal/users/{user_id}/account-internal:
|
|
get:
|
|
tags: [Internal]
|
|
operationId: internalUsersGetAccountInternal
|
|
summary: Server-to-server fetch of an account aggregate (gateway-only)
|
|
security: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/UserID"
|
|
responses:
|
|
"200":
|
|
description: Account aggregate enriched for gateway flows.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AccountResponse"
|
|
"404":
|
|
$ref: "#/components/responses/NotFoundError"
|
|
"501":
|
|
$ref: "#/components/responses/NotImplementedError"
|
|
"500":
|
|
$ref: "#/components/responses/InternalError"
|
|
components:
|
|
parameters:
|
|
AcceptLanguage:
|
|
name: Accept-Language
|
|
in: header
|
|
required: false
|
|
description: |
|
|
Optional RFC 9110 Accept-Language header forwarded by gateway. Backend
|
|
uses it as a fallback locale source when the request body does not
|
|
carry an explicit `locale` field.
|
|
schema:
|
|
type: string
|
|
XUserID:
|
|
name: X-User-ID
|
|
in: header
|
|
required: true
|
|
description: |
|
|
Trusted UUID identifying the calling user. Injected by gateway after
|
|
request signature verification. Backend never re-derives identity from
|
|
the request body on the user surface.
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
GameID:
|
|
name: game_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
ApplicationID:
|
|
name: application_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
InviteID:
|
|
name: invite_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
MembershipID:
|
|
name: membership_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
NotificationID:
|
|
name: notification_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
DeliveryID:
|
|
name: delivery_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
UserID:
|
|
name: user_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
DeviceSessionID:
|
|
name: device_session_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
EngineVersionID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
Username:
|
|
name: username
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
Turn:
|
|
name: turn
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
Page:
|
|
name: page
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
default: 1
|
|
PageSize:
|
|
name: page_size
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 200
|
|
default: 50
|
|
securitySchemes:
|
|
UserHeader:
|
|
type: apiKey
|
|
in: header
|
|
name: X-User-ID
|
|
description: |
|
|
The trusted UUID forwarded by gateway after the device-session
|
|
signature has been verified.
|
|
AdminBasicAuth:
|
|
type: http
|
|
scheme: basic
|
|
description: |
|
|
Basic Auth credentials checked against `admin_accounts` with bcrypt
|
|
cost 12. Failed authentication returns `401` with
|
|
`WWW-Authenticate: Basic realm="galaxy-admin"`.
|
|
schemas:
|
|
HealthzResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [status]
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [ok]
|
|
ReadyzResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [status]
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [ready, starting]
|
|
ErrorBody:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [code, message]
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: |
|
|
Stable machine-readable failure marker. The closed set is
|
|
`not_implemented`, `invalid_request`, `unauthorized`, `not_found`,
|
|
`conflict`, `method_not_allowed`, `internal_error`,
|
|
`service_unavailable`.
|
|
enum:
|
|
- not_implemented
|
|
- invalid_request
|
|
- unauthorized
|
|
- forbidden
|
|
- not_found
|
|
- conflict
|
|
- method_not_allowed
|
|
- internal_error
|
|
- service_unavailable
|
|
message:
|
|
type: string
|
|
description: Human-readable client-safe failure description.
|
|
ErrorResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
$ref: "#/components/schemas/ErrorBody"
|
|
PublicAuthSendEmailCodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [email]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
locale:
|
|
type: string
|
|
description: Optional BCP 47 locale tag preferred for the delivered code.
|
|
PublicAuthSendEmailCodeResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [challenge_id]
|
|
properties:
|
|
challenge_id:
|
|
type: string
|
|
description: Opaque identifier of the issued challenge.
|
|
PublicAuthConfirmEmailCodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [challenge_id, code, client_public_key, time_zone]
|
|
properties:
|
|
challenge_id:
|
|
type: string
|
|
code:
|
|
type: string
|
|
description: Verification code delivered by mail.
|
|
client_public_key:
|
|
type: string
|
|
description: Standard base64-encoded raw 32-byte Ed25519 public key.
|
|
time_zone:
|
|
type: string
|
|
description: IANA time-zone identifier provided by the client.
|
|
PublicAuthConfirmEmailCodeResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [device_session_id]
|
|
properties:
|
|
device_session_id:
|
|
type: string
|
|
format: uuid
|
|
ActorRef:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [type]
|
|
properties:
|
|
type:
|
|
type: string
|
|
id:
|
|
type: string
|
|
EntitlementSnapshot:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- plan_code
|
|
- is_paid
|
|
- source
|
|
- actor
|
|
- reason_code
|
|
- starts_at
|
|
- max_registered_race_names
|
|
- updated_at
|
|
properties:
|
|
plan_code:
|
|
type: string
|
|
enum: [free, monthly, yearly, permanent]
|
|
description: |
|
|
Closed tier vocabulary. The wire field name is `plan_code`;
|
|
the storage column is `entitlement_snapshots.tier`.
|
|
is_paid:
|
|
type: boolean
|
|
source:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
reason_code:
|
|
type: string
|
|
starts_at:
|
|
type: string
|
|
format: date-time
|
|
ends_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
max_registered_race_names:
|
|
type: integer
|
|
description: |
|
|
Derived from the tier policy table. `free` accounts get 1;
|
|
`monthly`, `yearly`, and `permanent` accounts get 5 in MVP.
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
ActiveSanction:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [sanction_code, scope, reason_code, actor, applied_at]
|
|
properties:
|
|
sanction_code:
|
|
type: string
|
|
scope:
|
|
type: string
|
|
reason_code:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
applied_at:
|
|
type: string
|
|
format: date-time
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
ActiveLimit:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [limit_code, value, reason_code, actor, applied_at]
|
|
properties:
|
|
limit_code:
|
|
type: string
|
|
value:
|
|
type: integer
|
|
reason_code:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
applied_at:
|
|
type: string
|
|
format: date-time
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
Account:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- user_id
|
|
- email
|
|
- user_name
|
|
- preferred_language
|
|
- time_zone
|
|
- entitlement
|
|
- active_sanctions
|
|
- active_limits
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
format: email
|
|
user_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
preferred_language:
|
|
type: string
|
|
time_zone:
|
|
type: string
|
|
declared_country:
|
|
type: string
|
|
entitlement:
|
|
$ref: "#/components/schemas/EntitlementSnapshot"
|
|
active_sanctions:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ActiveSanction"
|
|
active_limits:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ActiveLimit"
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
AccountResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [account]
|
|
properties:
|
|
account:
|
|
$ref: "#/components/schemas/Account"
|
|
UpdateProfileRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
display_name:
|
|
type: string
|
|
description: Replacement display name; an empty value clears the field.
|
|
UpdateSettingsRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
preferred_language:
|
|
type: string
|
|
time_zone:
|
|
type: string
|
|
GameSummary:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- game_id
|
|
- game_name
|
|
- game_type
|
|
- status
|
|
- min_players
|
|
- max_players
|
|
- enrollment_ends_at
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
game_name:
|
|
type: string
|
|
game_type:
|
|
type: string
|
|
enum: [public, private]
|
|
description: |
|
|
Wire alias for `visibility`; values match the storage column
|
|
`games.visibility`. `public` games are admin-created and
|
|
carry `owner_user_id IS NULL`; `private` games are owned by
|
|
the calling user.
|
|
status:
|
|
type: string
|
|
enum:
|
|
- draft
|
|
- enrollment_open
|
|
- ready_to_start
|
|
- starting
|
|
- start_failed
|
|
- running
|
|
- paused
|
|
- finished
|
|
- cancelled
|
|
owner_user_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
description: |
|
|
Owner user_id for private games; `null` for public games whose
|
|
ownership is collective and managed by administrators.
|
|
min_players:
|
|
type: integer
|
|
minimum: 1
|
|
max_players:
|
|
type: integer
|
|
minimum: 1
|
|
enrollment_ends_at:
|
|
type: string
|
|
format: date-time
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
GameSummaryPage:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/GameSummary"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
MyGamesListResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/GameSummary"
|
|
LobbyGameCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- game_name
|
|
- visibility
|
|
- min_players
|
|
- max_players
|
|
- start_gap_hours
|
|
- start_gap_players
|
|
- enrollment_ends_at
|
|
- turn_schedule
|
|
- target_engine_version
|
|
properties:
|
|
game_name:
|
|
type: string
|
|
minLength: 1
|
|
visibility:
|
|
type: string
|
|
enum: [private]
|
|
description: |
|
|
User-facing game creation always emits `private` games. Public
|
|
games are created by admins via `POST /api/v1/admin/games`.
|
|
description:
|
|
type: string
|
|
min_players:
|
|
type: integer
|
|
minimum: 1
|
|
max_players:
|
|
type: integer
|
|
minimum: 1
|
|
start_gap_hours:
|
|
type: integer
|
|
minimum: 0
|
|
start_gap_players:
|
|
type: integer
|
|
minimum: 0
|
|
enrollment_ends_at:
|
|
type: string
|
|
format: date-time
|
|
turn_schedule:
|
|
type: string
|
|
description: Five-field cron expression accepted by `pkg/cronutil.Parse`.
|
|
target_engine_version:
|
|
type: string
|
|
description: |
|
|
Engine version label (semver). Cross-checked against
|
|
`engine_versions` at start time; rejected if no enabled row
|
|
matches.
|
|
LobbyGameUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
description: |
|
|
Mutable lobby game fields (owner-only patch). Status transitions are
|
|
driven through dedicated endpoints (`open-enrollment`,
|
|
`ready-to-start`, `start`, `pause`, `resume`, `cancel`,
|
|
`retry-start`).
|
|
properties:
|
|
game_name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type: string
|
|
enrollment_ends_at:
|
|
type: string
|
|
format: date-time
|
|
turn_schedule:
|
|
type: string
|
|
target_engine_version:
|
|
type: string
|
|
min_players:
|
|
type: integer
|
|
minimum: 1
|
|
max_players:
|
|
type: integer
|
|
minimum: 1
|
|
start_gap_hours:
|
|
type: integer
|
|
minimum: 0
|
|
start_gap_players:
|
|
type: integer
|
|
minimum: 0
|
|
AdminGameCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- game_name
|
|
- min_players
|
|
- max_players
|
|
- start_gap_hours
|
|
- start_gap_players
|
|
- enrollment_ends_at
|
|
- turn_schedule
|
|
- target_engine_version
|
|
description: |
|
|
Admin-side public-game creation. The `visibility` of the created
|
|
record is hard-coded to `public` and `owner_user_id` is `NULL`.
|
|
properties:
|
|
game_name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type: string
|
|
min_players:
|
|
type: integer
|
|
minimum: 1
|
|
max_players:
|
|
type: integer
|
|
minimum: 1
|
|
start_gap_hours:
|
|
type: integer
|
|
minimum: 0
|
|
start_gap_players:
|
|
type: integer
|
|
minimum: 0
|
|
enrollment_ends_at:
|
|
type: string
|
|
format: date-time
|
|
turn_schedule:
|
|
type: string
|
|
target_engine_version:
|
|
type: string
|
|
LobbyGameDetail:
|
|
allOf:
|
|
- $ref: "#/components/schemas/GameSummary"
|
|
- type: object
|
|
additionalProperties: false
|
|
required:
|
|
- visibility
|
|
- turn_schedule
|
|
- target_engine_version
|
|
- start_gap_hours
|
|
- start_gap_players
|
|
- current_turn
|
|
- runtime_status
|
|
properties:
|
|
visibility:
|
|
type: string
|
|
enum: [public, private]
|
|
description:
|
|
type: string
|
|
turn_schedule:
|
|
type: string
|
|
target_engine_version:
|
|
type: string
|
|
start_gap_hours:
|
|
type: integer
|
|
start_gap_players:
|
|
type: integer
|
|
current_turn:
|
|
type: integer
|
|
runtime_status:
|
|
type: string
|
|
engine_health:
|
|
type: string
|
|
started_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
finished_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
LobbyGameStateChange:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [game_id, status]
|
|
properties:
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
status:
|
|
type: string
|
|
runtime_status:
|
|
type: string
|
|
LobbyApplicationSubmitRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [race_name]
|
|
properties:
|
|
race_name:
|
|
type: string
|
|
minLength: 1
|
|
LobbyApplicationDetail:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- application_id
|
|
- game_id
|
|
- applicant_user_id
|
|
- race_name
|
|
- status
|
|
- created_at
|
|
properties:
|
|
application_id:
|
|
type: string
|
|
format: uuid
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
applicant_user_id:
|
|
type: string
|
|
format: uuid
|
|
race_name:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [pending, approved, rejected]
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
decided_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
LobbyApplicationList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/LobbyApplicationDetail"
|
|
LobbyInviteIssueRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
description: |
|
|
Issues either a user-bound invite (when `invited_user_id` is set)
|
|
or a one-shot code-based invite (when omitted). The server
|
|
generates the redemption `code` for the latter.
|
|
properties:
|
|
invited_user_id:
|
|
type: string
|
|
format: uuid
|
|
race_name:
|
|
type: string
|
|
minLength: 1
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
LobbyInviteDetail:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- invite_id
|
|
- game_id
|
|
- inviter_user_id
|
|
- status
|
|
- race_name
|
|
- created_at
|
|
- expires_at
|
|
properties:
|
|
invite_id:
|
|
type: string
|
|
format: uuid
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
inviter_user_id:
|
|
type: string
|
|
format: uuid
|
|
invited_user_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
code:
|
|
type: string
|
|
nullable: true
|
|
race_name:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [pending, redeemed, declined, revoked, expired]
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
decided_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
LobbyInviteList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/LobbyInviteDetail"
|
|
LobbyMembershipDetail:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- membership_id
|
|
- game_id
|
|
- user_id
|
|
- race_name
|
|
- canonical_key
|
|
- status
|
|
- joined_at
|
|
properties:
|
|
membership_id:
|
|
type: string
|
|
format: uuid
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
race_name:
|
|
type: string
|
|
canonical_key:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [active, removed, blocked]
|
|
joined_at:
|
|
type: string
|
|
format: date-time
|
|
removed_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
LobbyMembershipList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/LobbyMembershipDetail"
|
|
RaceNameDetail:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [name, canonical, status, owner_user_id]
|
|
properties:
|
|
name:
|
|
type: string
|
|
canonical:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [registered, reservation, pending_registration]
|
|
owner_user_id:
|
|
type: string
|
|
format: uuid
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
source_game_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
reserved_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
registered_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
RaceNameList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/RaceNameDetail"
|
|
RaceNameRegisterRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
EngineCommand:
|
|
type: object
|
|
additionalProperties: true
|
|
description: |
|
|
Engine command request body. The schema is permissive because the
|
|
engine proxy passes the body through verbatim; the typed shape
|
|
lives in `pkg/model/rest.Command` and is enforced by
|
|
`internal/engineclient` before the engine call leaves backend.
|
|
EngineOrder:
|
|
type: object
|
|
additionalProperties: true
|
|
description: |
|
|
Engine order request body. Permissive on the wire; typed shape
|
|
lives in `pkg/model/order.Order`.
|
|
PassthroughObject:
|
|
type: object
|
|
additionalProperties: true
|
|
description: |
|
|
Permissive placeholder used for engine pass-through responses
|
|
(`pkg/model/{rest,report}` types are the authoritative shape).
|
|
AdminAccount:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [username, created_at]
|
|
properties:
|
|
username:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
last_used_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
disabled_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
AdminAccountList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AdminAccount"
|
|
AdminAccountCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [username, password]
|
|
properties:
|
|
username:
|
|
type: string
|
|
password:
|
|
type: string
|
|
format: password
|
|
AdminAccountResetPasswordRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [password]
|
|
properties:
|
|
password:
|
|
type: string
|
|
format: password
|
|
AdminUserList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Account"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
AdminUserSanctionRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [sanction_code, scope, reason_code, actor]
|
|
properties:
|
|
sanction_code:
|
|
type: string
|
|
enum: [permanent_block]
|
|
description: |
|
|
Closed MVP set; only `permanent_block` is supported. Applying
|
|
it triggers the in-process cascade (revoke all sessions,
|
|
release lobby memberships and Race Name Directory entries).
|
|
scope:
|
|
type: string
|
|
reason_code:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
AdminUserLimitRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [limit_code, value, reason_code, actor]
|
|
properties:
|
|
limit_code:
|
|
type: string
|
|
value:
|
|
type: integer
|
|
reason_code:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
AdminUserEntitlementRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [tier, source, actor]
|
|
properties:
|
|
tier:
|
|
type: string
|
|
enum: [free, monthly, yearly, permanent]
|
|
source:
|
|
type: string
|
|
actor:
|
|
$ref: "#/components/schemas/ActorRef"
|
|
reason_code:
|
|
type: string
|
|
starts_at:
|
|
type: string
|
|
format: date-time
|
|
ends_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
AdminGameList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/LobbyGameDetail"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
AdminGameBanMemberRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [user_id, reason]
|
|
properties:
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
reason:
|
|
type: string
|
|
minLength: 1
|
|
RuntimeRecord:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [game_id, status]
|
|
properties:
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
status:
|
|
type: string
|
|
current_container_id:
|
|
type: string
|
|
image_ref:
|
|
type: string
|
|
started_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
last_observed_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
RuntimeOperation:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [operation_id, game_id, op, status, started_at]
|
|
properties:
|
|
operation_id:
|
|
type: string
|
|
format: uuid
|
|
game_id:
|
|
type: string
|
|
format: uuid
|
|
op:
|
|
type: string
|
|
status:
|
|
type: string
|
|
started_at:
|
|
type: string
|
|
format: date-time
|
|
finished_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
error:
|
|
type: string
|
|
RuntimePatchRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [target_version]
|
|
properties:
|
|
target_version:
|
|
type: string
|
|
description: Semver-patch target inside the same major/minor line.
|
|
EngineVersion:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [version, image_ref, enabled, created_at]
|
|
properties:
|
|
version:
|
|
type: string
|
|
image_ref:
|
|
type: string
|
|
enabled:
|
|
type: boolean
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
EngineVersionList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/EngineVersion"
|
|
EngineVersionCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [version, image_ref]
|
|
properties:
|
|
version:
|
|
type: string
|
|
image_ref:
|
|
type: string
|
|
enabled:
|
|
type: boolean
|
|
EngineVersionUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
image_ref:
|
|
type: string
|
|
enabled:
|
|
type: boolean
|
|
MailDelivery:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [delivery_id, template_id, status, attempts, created_at]
|
|
properties:
|
|
delivery_id:
|
|
type: string
|
|
format: uuid
|
|
template_id:
|
|
type: string
|
|
idempotency_key:
|
|
type: string
|
|
status:
|
|
type: string
|
|
attempts:
|
|
type: integer
|
|
next_attempt_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
MailDeliveryList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/MailDelivery"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
MailAttempt:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [attempt_id, delivery_id, attempt_no, started_at]
|
|
properties:
|
|
attempt_id:
|
|
type: string
|
|
format: uuid
|
|
delivery_id:
|
|
type: string
|
|
format: uuid
|
|
attempt_no:
|
|
type: integer
|
|
started_at:
|
|
type: string
|
|
format: date-time
|
|
finished_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
outcome:
|
|
type: string
|
|
error:
|
|
type: string
|
|
MailAttemptList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/MailAttempt"
|
|
MailDeadLetter:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [dead_letter_id, delivery_id, archived_at]
|
|
properties:
|
|
dead_letter_id:
|
|
type: string
|
|
format: uuid
|
|
delivery_id:
|
|
type: string
|
|
format: uuid
|
|
archived_at:
|
|
type: string
|
|
format: date-time
|
|
reason:
|
|
type: string
|
|
MailDeadLetterList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/MailDeadLetter"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
NotificationDetail:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [notification_id, kind, idempotency_key, created_at]
|
|
properties:
|
|
notification_id:
|
|
type: string
|
|
format: uuid
|
|
kind:
|
|
type: string
|
|
idempotency_key:
|
|
type: string
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
payload:
|
|
type: object
|
|
additionalProperties: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
NotificationList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/NotificationDetail"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
NotificationDeadLetter:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [dead_letter_id, notification_id, archived_at]
|
|
properties:
|
|
dead_letter_id:
|
|
type: string
|
|
format: uuid
|
|
notification_id:
|
|
type: string
|
|
format: uuid
|
|
archived_at:
|
|
type: string
|
|
format: date-time
|
|
reason:
|
|
type: string
|
|
NotificationDeadLetterList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/NotificationDeadLetter"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
NotificationMalformed:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [id, received_at]
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
received_at:
|
|
type: string
|
|
format: date-time
|
|
payload:
|
|
type: object
|
|
additionalProperties: true
|
|
reason:
|
|
type: string
|
|
NotificationMalformedList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items, page, page_size, total]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/NotificationMalformed"
|
|
page:
|
|
type: integer
|
|
page_size:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
GeoCountryCounter:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [country, count]
|
|
properties:
|
|
country:
|
|
type: string
|
|
description: ISO 3166-1 alpha-2 country code.
|
|
count:
|
|
type: integer
|
|
last_seen_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
GeoCountryCounterList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [user_id, items]
|
|
properties:
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/GeoCountryCounter"
|
|
DeviceSession:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [device_session_id, user_id, status, created_at]
|
|
properties:
|
|
device_session_id:
|
|
type: string
|
|
format: uuid
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
status:
|
|
type: string
|
|
client_public_key:
|
|
type: string
|
|
description: Standard base64-encoded raw 32-byte Ed25519 public key.
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
revoked_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
last_seen_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
DeviceSessionRevocationSummary:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [user_id, revoked_count]
|
|
properties:
|
|
user_id:
|
|
type: string
|
|
format: uuid
|
|
revoked_count:
|
|
type: integer
|
|
UserSessionList:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/DeviceSession"
|
|
responses:
|
|
NotImplementedError:
|
|
description: Endpoint is documented but not implemented yet.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
placeholder:
|
|
value:
|
|
error:
|
|
code: not_implemented
|
|
message: endpoint is not implemented yet
|
|
InvalidRequestError:
|
|
description: Request body or field values are invalid.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
invalidRequest:
|
|
value:
|
|
error:
|
|
code: invalid_request
|
|
message: request payload is invalid
|
|
UnauthorizedError:
|
|
description: Basic authentication credentials are missing or rejected.
|
|
headers:
|
|
WWW-Authenticate:
|
|
description: Basic challenge advertised on rejected admin requests.
|
|
schema:
|
|
type: string
|
|
example: Basic realm="galaxy-admin"
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
unauthorized:
|
|
value:
|
|
error:
|
|
code: unauthorized
|
|
message: basic authentication is required
|
|
ForbiddenError:
|
|
description: Caller is authenticated but not allowed to perform the action.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
forbidden:
|
|
value:
|
|
error:
|
|
code: forbidden
|
|
message: caller is not authorized for this action
|
|
NotFoundError:
|
|
description: The requested resource was not found.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
notFound:
|
|
value:
|
|
error:
|
|
code: not_found
|
|
message: resource was not found
|
|
ConflictError:
|
|
description: The request conflicts with the current state of the target resource.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
conflict:
|
|
value:
|
|
error:
|
|
code: conflict
|
|
message: resource already exists
|
|
MethodNotAllowedError:
|
|
description: Request method is not allowed for the target route.
|
|
headers:
|
|
Allow:
|
|
description: Comma-separated list of accepted methods.
|
|
schema:
|
|
type: string
|
|
example: GET
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
methodNotAllowed:
|
|
value:
|
|
error:
|
|
code: method_not_allowed
|
|
message: request method is not allowed for this route
|
|
InternalError:
|
|
description: Internal backend error while processing the request.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
internalError:
|
|
value:
|
|
error:
|
|
code: internal_error
|
|
message: internal server error
|
|
ServiceUnavailableError:
|
|
description: Backend is starting up or temporarily cannot serve the request.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
unavailable:
|
|
value:
|
|
error:
|
|
code: service_unavailable
|
|
message: backend is not ready
|