Files
website/server/swagger/swagger-output.json
Claude f8db61025b Audit and fix Swagger/OpenAPI accuracy; regenerate served spec
The route-level annotations were 100% present, but the committed/served
spec (swagger-output.json) was stale and several response schemas had
drifted from the controllers. This aligns the docs with actual behavior
and regenerates the spec.

Served spec was stale (64/67 operations). Regenerating picks up three
routes that were added after the last generation:
  - POST /api/v1/auth/sso/totp
  - GET  /api/v1/admin/discord-bot/config
  - PUT  /api/v1/admin/discord-bot/config
plus a stale /auth/logout summary.

Response-shape corrections (annotation now matches controller output):
  - Mutation endpoints do NOT return the generic { message } envelope.
    Deletes echo { id } / { slug }; toggles return { deleted },
    { unlinked }, { totp_enabled }, or { ip, removed }. Documented as-is
    via new DeletedId/DeletedSlug/DeletedFlag/UnlinkedFlag/TotpState/
    UnbanResult components. (The API is intentionally inconsistent here;
    recorded rather than normalized — see follow-up note.)
  - POST /account/totp/setup: otpauth_url -> otpauthUrl (TotpSetup)
  - PUT  /admin/site-mode: { mode } -> { site_mode, changed_at, changed_by }
  - GET  /account: full User -> AccountStatus (id/username/role/totp_enabled)
  - GET  /account/identities: add linked_at (LinkedIdentity)
  - GET  /public/status: add status_message (PublicStatus)
  - POST /auth/sso/totp: user is SafeUser, not full User
  - GET  /dashboard: description/shape corrected (posts+users, no wiki)

Schema completeness:
  - Provider (public discovery): { id, name, icon, loginUrl, priority },
    not { id, name, kind }
  - ProviderConfig: add hasSecret, builtin, health (ProviderHealth)
  - Post: add excerpt, author_id, published_at
  - MobileTokenResponse.expiresIn: duration string ("15m"), not integer

Config: declare the Admin · Discord Bot tag (was used but undeclared).

Auth model and the internal/external boundary were verified correct and
left unchanged: cookie + bearer are both accepted on session routes (dual
security annotations are accurate), and /internal/* runs on a separate
listener already excluded from the scan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rao86n5cXpwAyjdBFEshV
2026-07-04 22:51:16 -05:00

6953 lines
182 KiB
JSON

{
"openapi": "3.0.0",
"info": {
"title": "UOMysticmoon API",
"version": "1.0.0",
"description": "REST API for the UOMysticmoon website, wiki and admin panel — a private Ultima Online shard.\n\n### Authentication\n- **Web / admin panel** uses an httpOnly session cookie (`uomm_token`) issued by `POST /api/v1/auth/login` (plus `/login/totp` when 2FA is enabled).\n- **Native / mobile clients** use bearer access tokens from `POST /api/v1/auth/mobile/login`, refreshed via `/auth/mobile/refresh`.\n\nEndpoints under `/api/v1/admin/**` require a valid session; some are further restricted to the `admin` role (editors are limited to content)."
},
"servers": [
{
"url": "/",
"description": "Same-origin (current host)"
},
{
"url": "http://localhost:3000",
"description": "Local development"
}
],
"tags": [
{
"name": "Health",
"description": "Liveness probe"
},
{
"name": "Auth",
"description": "Web session login/logout (cookie + TOTP)"
},
{
"name": "Auth · Mobile",
"description": "Native bearer-token login, refresh and logout"
},
{
"name": "Auth · SSO",
"description": "OAuth2 / OIDC provider discovery and redirect flow"
},
{
"name": "Public",
"description": "Unauthenticated site content (settings, posts, wiki, contact)"
},
{
"name": "Admin · Account",
"description": "Self-service account security (2FA, linked identities)"
},
{
"name": "Admin · Dashboard",
"description": "Dashboard summary and site mode"
},
{
"name": "Admin · Posts",
"description": "News / five-on-friday / newsletter / screenshots + uploads"
},
{
"name": "Admin · Wiki",
"description": "Wiki pages, categories, tags and revisions"
},
{
"name": "Admin · Settings",
"description": "Site settings (admin only)"
},
{
"name": "Admin · Activity",
"description": "Admin activity log"
},
{
"name": "Admin · Bot Activity",
"description": "Bot-scoring/ban state and emergency unban (admin only)"
},
{
"name": "Admin · Discord Bot",
"description": "Discord bot token/config and live status (admin only)"
},
{
"name": "Admin · Auth Providers",
"description": "SSO provider configuration (admin only)"
},
{
"name": "Admin · Users",
"description": "User management (admin only)"
}
],
"paths": {
"/api/health": {
"get": {
"tags": [
"Health"
],
"summary": "Liveness probe",
"description": "",
"responses": {
"200": {
"description": "Service is up",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"example": "ok"
}
}
}
}
}
}
}
}
},
"/api/v1/auth/login": {
"post": {
"tags": [
"Auth"
],
"summary": "Log in with username and password",
"description": "On success sets the httpOnly session cookie. If the account has 2FA enabled, returns { totpRequired, challenge } instead and no cookie is set — complete login at POST /login/totp. Rate limited and behind bot/backoff guards.",
"responses": {
"200": {
"description": "Session issued, or TOTP challenge required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResponse"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Incorrect username or password",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Too many attempts (rate limited / backoff)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
}
}
}
},
"/api/v1/auth/login/totp": {
"post": {
"tags": [
"Auth"
],
"summary": "Complete login with a TOTP code",
"description": "Second step for 2FA accounts. Exchange the challenge from /login plus the current authenticator code for a session cookie.",
"responses": {
"200": {
"description": "Session issued",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResponse"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Invalid code or expired challenge",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Too many attempts (rate limited / backoff)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpLoginRequest"
}
}
}
}
}
},
"/api/v1/auth/logout": {
"post": {
"tags": [
"Auth"
],
"summary": "Log out (clear the cookie and revoke this session)",
"description": "",
"responses": {
"200": {
"description": "Logged out",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
}
}
}
},
"/api/v1/auth/me": {
"get": {
"tags": [
"Auth"
],
"summary": "Current authenticated user",
"description": "",
"responses": {
"200": {
"description": "The signed-in user",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"user": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/auth/mobile/login": {
"post": {
"tags": [
"Auth · Mobile"
],
"summary": "Native login → access + refresh tokens",
"description": "Bearer-token login for native clients. Single-request 2FA: if the account has TOTP on and no/invalid code is supplied, returns 401 { totpRequired: true } and the client retries with a code.",
"responses": {
"200": {
"description": "Access + refresh tokens",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MobileTokenResponse"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Invalid credentials, or a TOTP code is required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Too many attempts (rate limited / backoff)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MobileLoginRequest"
}
}
}
}
}
},
"/api/v1/auth/mobile/refresh": {
"post": {
"tags": [
"Auth · Mobile"
],
"summary": "Rotate a refresh token for a fresh token pair",
"description": "Refresh tokens are single-use: the presented token is revoked and a new access + refresh pair is issued. Reusing a rotated token fails with 401.",
"responses": {
"200": {
"description": "New access + refresh tokens",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MobileTokenResponse"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Invalid or expired session",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Too many refresh attempts",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MobileRefreshRequest"
}
}
}
}
}
},
"/api/v1/auth/mobile/logout": {
"post": {
"tags": [
"Auth · Mobile"
],
"summary": "Revoke the current (or all) refresh tokens",
"description": "Requires a valid bearer access token. Revokes the given refresh token, or every session for the user when { all: true }. Idempotent.",
"responses": {
"200": {
"description": "Logged out",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Missing or invalid bearer token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MobileLogoutRequest"
}
}
}
}
}
},
"/api/v1/auth/providers": {
"get": {
"tags": [
"Auth · SSO"
],
"summary": "List enabled SSO providers",
"description": "Public discovery used by the login page to render provider buttons. Never exposes secrets.",
"responses": {
"200": {
"description": "Enabled, valid providers",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Provider"
}
}
}
}
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/auth/sso/{provider}/start": {
"get": {
"tags": [
"Auth · SSO"
],
"summary": "Begin SSO login (redirect to the IdP)",
"description": "Sets a short-lived signed transaction cookie and 302-redirects to the provider authorize URL. On error redirects back to the login page with an sso_error query param.",
"parameters": [
{
"name": "provider",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id (e.g. google, discord)."
},
{
"name": "returnTo",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Internal /admin path to return to after login."
}
],
"responses": {
"302": {
"description": "Redirect to the identity provider (or back to the login page on error)"
}
}
}
},
"/api/v1/auth/sso/{provider}/link": {
"get": {
"tags": [
"Auth · SSO"
],
"summary": "Begin linking an SSO identity to the current account",
"description": "Requires an authenticated session; the signed transaction captures the acting user so the callback can attach the external identity.",
"parameters": [
{
"name": "provider",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id (e.g. google, discord)."
}
],
"responses": {
"302": {
"description": "Redirect to the identity provider (or back to the account page on error)"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/auth/sso/{provider}/callback": {
"get": {
"tags": [
"Auth · SSO"
],
"summary": "OAuth redirect target — completes login or linking",
"description": "The provider redirects here with code + state. On success sets the session cookie (login) or links the identity (link), then 302-redirects into /admin. Login is link-only: unknown identities are refused (sso_error=not_linked).",
"parameters": [
{
"name": "provider",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id (e.g. google, discord)."
},
{
"name": "error",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "code",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "OAuth authorization code."
},
{
"name": "state",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "OAuth state (matched against the tx cookie)."
}
],
"responses": {
"302": {
"description": "Redirect into /admin on success, or back to login/account with an error code"
}
}
}
},
"/api/v1/auth/sso/totp": {
"post": {
"tags": [
"Auth · SSO"
],
"summary": "Complete an SSO login with a TOTP code",
"description": "Second step when a linked account has 2FA enabled. Reads the staged pending-TOTP cookie set by the callback plus the current authenticator code, and on success sets the session cookie. Rate limited and behind bot/backoff guards.",
"responses": {
"200": {
"description": "Session issued",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"user": {
"$ref": "#/components/schemas/SafeUser"
},
"returnTo": {
"type": "string"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Invalid code or expired challenge",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Too many attempts (rate limited / backoff)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"code"
],
"properties": {
"code": {
"type": "string"
}
}
}
}
}
}
}
},
"/api/v1/public/settings": {
"get": {
"tags": [
"Public"
],
"summary": "Public site settings",
"description": "Whitelisted, non-sensitive settings the client needs to render the site.",
"responses": {
"200": {
"description": "Key/value settings",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/public/status": {
"get": {
"tags": [
"Public"
],
"summary": "Site mode / status",
"description": "Current site mode (live or maintenance) so the client can show the maintenance page.",
"responses": {
"200": {
"description": "Site status",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicStatus"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/public/contact": {
"post": {
"tags": [
"Public"
],
"summary": "Send a contact message",
"description": "Emails the site owner (or falls back to a mailto). Rate limited.",
"responses": {
"200": {
"description": "Message sent",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"429": {
"description": "Too many messages (rate limited)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"502": {
"description": "Mail delivery failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ContactRequest"
}
}
}
}
}
},
"/api/v1/public/posts/{category}": {
"get": {
"tags": [
"Public"
],
"summary": "List published posts in a category",
"description": "Gated by site mode: during maintenance only admins with a valid session see content.",
"parameters": [
{
"name": "category",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "news | five-on-friday | newsletter | screenshots"
}
],
"responses": {
"200": {
"description": "Published posts",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Post"
}
}
}
}
},
"404": {
"description": "Unknown category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/public/posts/{category}/{idOrSlug}": {
"get": {
"tags": [
"Public"
],
"summary": "Get a single published post",
"description": "",
"parameters": [
{
"name": "category",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Post category."
},
{
"name": "idOrSlug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Numeric id or slug."
}
],
"responses": {
"200": {
"description": "The post",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
},
"404": {
"description": "Unknown category or post not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/public/wiki": {
"get": {
"tags": [
"Public"
],
"summary": "List published wiki pages",
"description": "",
"parameters": [
{
"name": "q",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "category",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Published wiki pages",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/public/wiki/categories": {
"get": {
"tags": [
"Public"
],
"summary": "List wiki categories",
"description": "",
"responses": {
"200": {
"description": "Wiki categories",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WikiCategory"
}
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/public/wiki/tags": {
"get": {
"tags": [
"Public"
],
"summary": "List wiki tags",
"description": "",
"responses": {
"200": {
"description": "Wiki tags",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/public/wiki/{slug}": {
"get": {
"tags": [
"Public"
],
"summary": "Get a single published wiki page",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "The wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
},
"503": {
"description": "Service Unavailable"
}
}
}
},
"/api/v1/admin/account": {
"get": {
"tags": [
"Admin · Account"
],
"summary": "Get the current account (self)",
"description": "",
"responses": {
"200": {
"description": "The account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountStatus"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/account/totp/setup": {
"post": {
"tags": [
"Admin · Account"
],
"summary": "Begin 2FA enrollment (returns secret + QR)",
"description": "",
"responses": {
"200": {
"description": "otpauth URL and QR data to scan",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpSetup"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Two-factor already enabled",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/account/totp/enable": {
"post": {
"tags": [
"Admin · Account"
],
"summary": "Enable 2FA by confirming a code",
"description": "",
"responses": {
"200": {
"description": "2FA enabled",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpState"
}
}
}
},
"400": {
"description": "Setup not started, or invalid code",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Two-factor already enabled",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpCodeRequest"
}
}
}
}
}
},
"/api/v1/admin/account/totp/disable": {
"post": {
"tags": [
"Admin · Account"
],
"summary": "Disable 2FA by confirming a code",
"description": "",
"responses": {
"200": {
"description": "2FA disabled",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpState"
}
}
}
},
"400": {
"description": "Not enabled, or invalid code",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TotpCodeRequest"
}
}
}
}
}
},
"/api/v1/admin/account/identities": {
"get": {
"tags": [
"Admin · Account"
],
"summary": "List linked SSO identities (self)",
"description": "",
"responses": {
"200": {
"description": "Linked identities",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LinkedIdentity"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/account/identities/{provider}": {
"delete": {
"tags": [
"Admin · Account"
],
"summary": "Unlink an SSO identity (self)",
"description": "",
"parameters": [
{
"name": "provider",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id."
}
],
"responses": {
"200": {
"description": "Unlinked",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnlinkedFlag"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "No linked account for that provider",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/dashboard": {
"get": {
"tags": [
"Admin · Dashboard"
],
"summary": "Dashboard summary counts",
"description": "",
"responses": {
"200": {
"description": "Summary: site mode, last change, post/user counts and recent activity",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"site_mode": {
"type": "string",
"example": "live"
},
"last_change": {
"type": "object",
"properties": {
"at": {
"type": "string",
"nullable": true
},
"by": {
"type": "string",
"nullable": true
}
}
},
"counts": {
"type": "object",
"properties": {
"posts": {
"type": "object",
"additionalProperties": true
},
"users": {
"type": "integer"
}
}
},
"recent_activity": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/site-mode": {
"put": {
"tags": [
"Admin · Dashboard"
],
"summary": "Set site mode (admin only)",
"description": "Switch the site between live and maintenance.",
"responses": {
"200": {
"description": "Updated site mode",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SiteModeState"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SiteModeRequest"
}
}
}
}
}
},
"/api/v1/admin/posts": {
"get": {
"tags": [
"Admin · Posts"
],
"summary": "List all posts (including unpublished)",
"description": "",
"parameters": [
{
"name": "category",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Optional category filter."
}
],
"responses": {
"200": {
"description": "Posts",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Post"
}
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"Admin · Posts"
],
"summary": "Create a post",
"description": "",
"responses": {
"201": {
"description": "Created post",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
},
"400": {
"description": "Validation error or unknown category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PostCreateRequest"
}
}
}
}
}
},
"/api/v1/admin/posts/upload": {
"post": {
"tags": [
"Admin · Posts"
],
"summary": "Upload a post image (multipart)",
"description": "",
"responses": {
"201": {
"description": "Stored image URL",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"image_url": {
"type": "string",
"example": "/uploads/1700000000-abcd.png"
}
}
}
}
}
},
"400": {
"description": "No image / disallowed type",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"image": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
}
},
"/api/v1/admin/uploads": {
"post": {
"tags": [
"Admin · Posts"
],
"summary": "Upload an image for rich-text editors (multipart)",
"description": "",
"responses": {
"201": {
"description": "Stored file URL",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UploadResponse"
}
}
}
},
"400": {
"description": "No file / disallowed type",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"image": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
}
},
"/api/v1/admin/posts/{id}": {
"get": {
"tags": [
"Admin · Posts"
],
"summary": "Get a post by id",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Post id."
}
],
"responses": {
"200": {
"description": "The post",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"put": {
"tags": [
"Admin · Posts"
],
"summary": "Update a post",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Post id."
}
],
"responses": {
"200": {
"description": "Updated post",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
},
"400": {
"description": "Validation error or unknown category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PostCreateRequest"
}
}
}
}
},
"delete": {
"tags": [
"Admin · Posts"
],
"summary": "Delete a post",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Post id."
}
],
"responses": {
"200": {
"description": "Deleted (echoes the id)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeletedId"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/posts/{id}/publish": {
"patch": {
"tags": [
"Admin · Posts"
],
"summary": "Publish / unpublish a post",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Post id."
}
],
"responses": {
"200": {
"description": "Updated post",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublishRequest"
}
}
}
}
}
},
"/api/v1/admin/wiki/categories": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "List wiki categories",
"description": "",
"responses": {
"200": {
"description": "Wiki categories",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WikiCategory"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"Admin · Wiki"
],
"summary": "Create a wiki category",
"description": "",
"responses": {
"201": {
"description": "Created category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiCategory"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Slug already exists",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiCategoryCreateRequest"
}
}
}
}
}
},
"/api/v1/admin/wiki/categories/{id}": {
"put": {
"tags": [
"Admin · Wiki"
],
"summary": "Update a wiki category",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Category id."
}
],
"responses": {
"200": {
"description": "Updated category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiCategory"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Slug already exists",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiCategoryCreateRequest"
}
}
}
}
},
"delete": {
"tags": [
"Admin · Wiki"
],
"summary": "Delete a wiki category",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Category id."
}
],
"responses": {
"200": {
"description": "Deleted (echoes the id)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeletedId"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/wiki/tags": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "List wiki tags",
"description": "",
"responses": {
"200": {
"description": "Wiki tags",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/wiki": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "List all wiki pages (including unpublished)",
"description": "",
"parameters": [
{
"name": "q",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "category",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "status",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wiki pages",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"Admin · Wiki"
],
"summary": "Create a wiki page",
"description": "",
"responses": {
"201": {
"description": "Created wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"400": {
"description": "Validation error or unknown category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Slug already exists",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPageCreateRequest"
}
}
}
}
}
},
"/api/v1/admin/wiki/{slug}": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "Get a wiki page by slug",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "The wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"put": {
"tags": [
"Admin · Wiki"
],
"summary": "Update a wiki page (creates a revision)",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "Updated wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"400": {
"description": "Validation error or unknown category",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/WikiPageCreateRequest"
},
{
"type": "object",
"properties": {
"change_note": {
"type": "string",
"maxLength": 280
}
}
}
]
}
}
}
}
},
"delete": {
"tags": [
"Admin · Wiki"
],
"summary": "Delete a wiki page",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "Deleted (echoes the slug)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeletedSlug"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/wiki/{slug}/publish": {
"patch": {
"tags": [
"Admin · Wiki"
],
"summary": "Publish / unpublish a wiki page",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "Updated wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublishRequest"
}
}
}
}
}
},
"/api/v1/admin/wiki/{slug}/revisions": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "List revisions of a wiki page",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
}
],
"responses": {
"200": {
"description": "Revisions",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/wiki/{slug}/revisions/{id}": {
"get": {
"tags": [
"Admin · Wiki"
],
"summary": "Get a single wiki revision",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
},
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Revision id."
}
],
"responses": {
"200": {
"description": "The revision",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/wiki/{slug}/revisions/{id}/restore": {
"post": {
"tags": [
"Admin · Wiki"
],
"summary": "Restore a wiki page to a revision",
"description": "",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Wiki page slug."
},
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Revision id to restore."
}
],
"responses": {
"200": {
"description": "Restored wiki page",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WikiPage"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/settings": {
"get": {
"tags": [
"Admin · Settings"
],
"summary": "Get all site settings (admin only)",
"description": "",
"responses": {
"200": {
"description": "All settings",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"put": {
"tags": [
"Admin · Settings"
],
"summary": "Update site settings (admin only)",
"description": "",
"responses": {
"200": {
"description": "Updated settings",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"400": {
"description": "Body must be an object of key/value settings",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true,
"description": "An object of key/value settings."
}
}
}
}
}
},
"/api/v1/admin/activity": {
"get": {
"tags": [
"Admin · Activity"
],
"summary": "List recent admin activity",
"description": "",
"parameters": [
{
"name": "offset",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer"
},
"description": "Max rows to return."
}
],
"responses": {
"200": {
"description": "Activity entries",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/bot-activity": {
"get": {
"tags": [
"Admin · Bot Activity"
],
"summary": "Bot-scoring / ban state and recent events (admin only)",
"description": "",
"responses": {
"200": {
"description": "Banned IPs, scores and recent events",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/bot-activity/unban": {
"post": {
"tags": [
"Admin · Bot Activity"
],
"summary": "Emergency unban an IP (admin only)",
"description": "",
"responses": {
"200": {
"description": "Unbanned (echoes the ip and whether an entry was cleared)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnbanResult"
}
}
}
},
"400": {
"description": "Invalid IP",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnbanRequest"
}
}
}
}
}
},
"/api/v1/admin/discord-bot/config": {
"get": {
"tags": [
"Admin · Discord Bot"
],
"summary": "Get Discord bot config + live status (admin only)",
"description": "",
"responses": {
"200": {
"description": "Masked config + live status",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"put": {
"tags": [
"Admin · Discord Bot"
],
"summary": "Save Discord bot config (admin only)",
"description": "token is write-only — omit/blank it to keep the existing one unchanged.",
"responses": {
"200": {
"description": "Updated config + live status",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"400": {
"description": "Validation error, invalid token, or missing token while enabling",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"guildId": {
"type": "string"
},
"token": {
"type": "string"
},
"enabled": {
"type": "boolean"
}
}
}
}
}
}
}
},
"/api/v1/admin/auth/providers": {
"get": {
"tags": [
"Admin · Auth Providers"
],
"summary": "List configured SSO providers (admin only)",
"description": "",
"responses": {
"200": {
"description": "Providers (secrets stripped)",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ProviderConfig"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"Admin · Auth Providers"
],
"summary": "Create a custom SSO provider (admin only)",
"description": "Built-in providers (google, discord) are configured via PUT, not created here.",
"responses": {
"201": {
"description": "Created provider",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProviderConfig"
}
}
}
},
"400": {
"description": "Validation error, or a built-in/invalid kind",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Provider id already exists",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProviderCreateRequest"
}
}
}
}
}
},
"/api/v1/admin/auth/providers/{id}": {
"put": {
"tags": [
"Admin · Auth Providers"
],
"summary": "Update an SSO provider (admin only)",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id."
}
],
"responses": {
"200": {
"description": "Updated provider",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProviderConfig"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Provider not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProviderCreateRequest"
}
}
}
}
},
"delete": {
"tags": [
"Admin · Auth Providers"
],
"summary": "Delete a custom SSO provider (admin only)",
"description": "Built-in providers cannot be deleted — disable them instead.",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Provider id."
}
],
"responses": {
"200": {
"description": "Deleted",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeletedFlag"
}
}
}
},
"400": {
"description": "Built-in provider cannot be deleted",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Provider not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
},
"/api/v1/admin/users": {
"get": {
"tags": [
"Admin · Users"
],
"summary": "List users (admin only)",
"description": "",
"responses": {
"200": {
"description": "Users",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/User"
}
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"Admin · Users"
],
"summary": "Create a user (admin only)",
"description": "",
"responses": {
"201": {
"description": "Created user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Username already taken",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateRequest"
}
}
}
}
}
},
"/api/v1/admin/users/{id}": {
"put": {
"tags": [
"Admin · Users"
],
"summary": "Update a user (admin only)",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "User id."
}
],
"responses": {
"200": {
"description": "Updated user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Validation error, or cannot demote the last admin",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Username already taken",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateRequest"
}
}
}
}
},
"delete": {
"tags": [
"Admin · Users"
],
"summary": "Delete a user (admin only)",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "User id."
}
],
"responses": {
"200": {
"description": "Deleted (echoes the id)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeletedId"
}
}
}
},
"400": {
"description": "Cannot delete your own account or the last admin",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Not authenticated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Admin role required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Internal Server Error"
}
},
"security": [
{
"cookieAuth": []
},
{
"bearerAuth": []
}
]
}
}
},
"components": {
"securitySchemes": {
"cookieAuth": {
"type": "apiKey",
"in": "cookie",
"name": "uomm_token",
"description": "Session JWT set as an httpOnly cookie by POST /api/v1/auth/login."
},
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": "Access token from POST /api/v1/auth/mobile/login (or /refresh)."
}
},
"schemas": {
"Error": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"message": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Not found"
}
}
}
}
}
}
},
"ValidationError": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"errors": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "array"
},
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"type": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "field"
}
}
},
"msg": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Invalid value"
}
}
},
"path": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "username"
}
}
},
"location": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "body"
}
}
}
}
}
}
}
}
}
}
}
}
},
"SafeUser": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 1
}
}
},
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"role": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"admin",
"editor"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "admin"
}
}
}
}
}
}
},
"LoginRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"username",
"password"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"password": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "password"
},
"example": {
"type": "string",
"example": "super-secret"
}
}
},
"company": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Honeypot — must be empty for humans."
},
"example": {
"type": "string",
"example": ""
}
}
}
}
}
}
},
"LoginResponse": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Either a session (user) or, for 2FA accounts, a TOTP challenge to complete at /login/totp."
},
"properties": {
"type": "object",
"properties": {
"user": {
"$ref": "#/components/schemas/SafeUser"
},
"totpRequired": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"challenge": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Signed challenge token for the TOTP step."
}
}
}
}
}
}
},
"TotpLoginRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"challenge",
"code"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"challenge": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Token returned by /login when totpRequired."
}
}
},
"code": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "123456"
}
}
}
}
}
}
},
"MobileLoginRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"username",
"password"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"password": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "password"
},
"example": {
"type": "string",
"example": "super-secret"
}
}
},
"code": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "TOTP code (only when 2FA is enabled)."
},
"example": {
"type": "string",
"example": "123456"
}
}
}
}
}
}
},
"MobileTokenResponse": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"accessToken": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Short-lived bearer JWT."
}
}
},
"refreshToken": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Long-lived, revocable refresh token."
}
}
},
"expiresIn": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Access token lifetime as a duration string (zeit/ms format, e.g. \"15m\")."
},
"example": {
"type": "string",
"example": "15m"
}
}
},
"user": {
"$ref": "#/components/schemas/SafeUser"
}
}
}
}
},
"MobileRefreshRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"refreshToken"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"refreshToken": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
}
}
}
}
},
"MobileLogoutRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"refreshToken": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Revoke a single session."
}
}
},
"all": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"description": {
"type": "string",
"example": "Revoke every session for the user."
},
"example": {
"type": "boolean",
"example": false
}
}
}
}
}
}
},
"Message": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"message": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Logged out."
}
}
}
}
}
}
},
"ContactRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"message"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"message": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 5000
},
"example": {
"type": "string",
"example": "When does the shard launch?"
}
}
},
"email": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "email"
},
"example": {
"type": "string",
"example": "player@example.com"
}
}
},
"name": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 100
},
"example": {
"type": "string",
"example": "Lord British"
}
}
}
}
}
}
},
"Provider": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "google"
}
}
},
"name": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Google"
}
}
},
"icon": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Icon hint — the provider kind ('google' | 'discord' | 'oidc' | 'oauth2')."
},
"example": {
"type": "string",
"example": "google"
}
}
},
"loginUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Relative URL to begin the redirect flow."
},
"example": {
"type": "string",
"example": "/api/v1/auth/sso/google/start"
}
}
},
"priority": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"description": {
"type": "string",
"example": "Sort order (ascending)."
},
"example": {
"type": "number",
"example": 1
}
}
}
}
}
}
},
"ProviderConfig": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "okta"
}
}
},
"kind": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"google",
"discord",
"oidc",
"oauth2"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "oidc"
}
}
},
"name": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Okta"
}
}
},
"enabled": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"clientId": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"hasSecret": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"description": {
"type": "string",
"example": "Whether a client secret is stored (the secret itself is never returned)."
},
"example": {
"type": "boolean",
"example": true
}
}
},
"authorizeUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"tokenUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"userinfoUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"scopes": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "openid email profile"
}
}
},
"priority": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 10
}
}
},
"builtin": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"description": {
"type": "string",
"example": "True for the fixed google/discord providers."
},
"example": {
"type": "boolean",
"example": false
}
}
},
"health": {
"$ref": "#/components/schemas/ProviderHealth"
}
}
}
}
},
"ProviderHealth": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Config-completeness check that gates whether a provider is offered to end users."
},
"properties": {
"type": "object",
"properties": {
"valid": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"missing": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "array"
},
"description": {
"type": "string",
"example": "Names of required config fields that are still missing."
},
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"example": {
"type": "array",
"example": [],
"items": {}
}
}
}
}
}
}
},
"ProviderCreateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"id",
"kind",
"name"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"pattern": {
"type": "string",
"example": "^[a-z0-9-]+$"
},
"example": {
"type": "string",
"example": "okta"
}
}
},
"kind": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"oidc",
"oauth2"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "oidc"
}
}
},
"name": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 80
},
"example": {
"type": "string",
"example": "Okta"
}
}
},
"enabled": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"clientId": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"secret": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "password"
}
}
},
"authorizeUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"tokenUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"userinfoUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "uri"
}
}
},
"scopes": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 500
},
"example": {
"type": "string",
"example": "openid email profile"
}
}
},
"priority": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 10
}
}
}
}
}
}
},
"Post": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 12
}
}
},
"category": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "news"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Server maintenance this weekend"
}
}
},
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "server-maintenance-this-weekend"
}
}
},
"excerpt": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"nullable": {
"type": "boolean",
"example": true
}
}
},
"body": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"nullable": {
"type": "boolean",
"example": true
}
}
},
"image_url": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"nullable": {
"type": "boolean",
"example": true
},
"example": {
"type": "string",
"example": "/uploads/1700000000-abcd.png"
}
}
},
"published": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"author_id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"nullable": {
"type": "boolean",
"example": true
},
"example": {
"type": "number",
"example": 1
}
}
},
"created_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
},
"updated_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
},
"published_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
},
"nullable": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"PostCreateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"category",
"title"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"category": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "news"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 200
},
"example": {
"type": "string",
"example": "Server maintenance this weekend"
}
}
},
"body": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"image_url": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "Required for the screenshots category."
}
}
},
"published": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": false
}
}
}
}
}
}
},
"PublishRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"published"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"published": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"UploadResponse": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"url": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "/uploads/1700000000-abcd.png"
}
}
}
}
}
}
},
"WikiPage": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 3
}
}
},
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "getting-started"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Getting Started"
}
}
},
"excerpt": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"body": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"category_id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"nullable": {
"type": "boolean",
"example": true
},
"example": {
"type": "number",
"example": 2
}
}
},
"published": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"tags": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "array"
},
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"example": {
"type": "array",
"example": [
"newbie",
"guide"
],
"items": {
"type": "string"
}
}
}
},
"created_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
},
"updated_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
}
}
}
}
},
"WikiPageCreateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"slug",
"title"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"pattern": {
"type": "string",
"example": "^[a-z0-9-]+$"
},
"example": {
"type": "string",
"example": "getting-started"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 200
},
"example": {
"type": "string",
"example": "Getting Started"
}
}
},
"excerpt": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 400
}
}
},
"body": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"category_id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"nullable": {
"type": "boolean",
"example": true
}
}
},
"published": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": false
}
}
},
"tags": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "array"
},
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
}
}
}
}
}
}
},
"WikiCategory": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 2
}
}
},
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "guides"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Guides"
}
}
},
"description": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
}
}
},
"sort_order": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 0
}
}
}
}
}
}
},
"WikiCategoryCreateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"slug",
"title"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"pattern": {
"type": "string",
"example": "^[a-z0-9-]+$"
},
"example": {
"type": "string",
"example": "guides"
}
}
},
"title": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 200
},
"example": {
"type": "string",
"example": "Guides"
}
}
},
"description": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"maxLength": {
"type": "number",
"example": 400
}
}
},
"sort_order": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 0
}
}
}
}
}
}
},
"User": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 1
}
}
},
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"role": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"admin",
"editor"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"totp_enabled": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
},
"last_login_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
},
"nullable": {
"type": "boolean",
"example": true
}
}
},
"created_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
}
}
}
}
},
"UserCreateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"username",
"password"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"minLength": {
"type": "number",
"example": 3
},
"maxLength": {
"type": "number",
"example": 32
},
"example": {
"type": "string",
"example": "editor1"
}
}
},
"password": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "password"
},
"minLength": {
"type": "number",
"example": 8
},
"maxLength": {
"type": "number",
"example": 64
}
}
},
"role": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"admin",
"editor"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "editor"
}
}
}
}
}
}
},
"TotpCodeRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"code"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"code": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "123456"
}
}
}
}
}
}
},
"SiteModeRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"mode"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"mode": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"live",
"maintenance"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "live"
}
}
}
}
}
}
},
"UnbanRequest": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"required": {
"type": "array",
"example": [
"ip"
],
"items": {
"type": "string"
}
},
"properties": {
"type": "object",
"properties": {
"ip": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "203.0.113.5"
}
}
}
}
}
}
},
"AccountStatus": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Self-service account security status (GET /admin/account)."
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 1
}
}
},
"username": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"role": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"admin",
"editor"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "admin"
}
}
},
"totp_enabled": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"TotpSetup": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Enrollment material returned by POST /account/totp/setup."
},
"properties": {
"type": "object",
"properties": {
"otpauthUrl": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "otpauth://totp/UOMysticmoon:admin?secret=..."
}
}
},
"qr": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"description": {
"type": "string",
"example": "QR code as a data: URL."
},
"example": {
"type": "string",
"example": "data:image/png;base64,iVBORw0KGgo..."
}
}
}
}
}
}
},
"TotpState": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Result of enabling/disabling 2FA."
},
"properties": {
"type": "object",
"properties": {
"totp_enabled": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"LinkedIdentity": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"provider": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "google"
}
}
},
"email": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "email"
},
"nullable": {
"type": "boolean",
"example": true
},
"example": {
"type": "string",
"example": "user@example.com"
}
}
},
"linked_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
}
}
}
}
},
"SiteModeState": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Result of PUT /admin/site-mode."
},
"properties": {
"type": "object",
"properties": {
"site_mode": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"live",
"maintenance"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "maintenance"
}
}
},
"changed_at": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"format": {
"type": "string",
"example": "date-time"
}
}
},
"changed_by": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "admin"
}
}
}
}
}
}
},
"PublicStatus": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "Public site status (GET /public/status)."
},
"properties": {
"type": "object",
"properties": {
"mode": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"enum": {
"type": "array",
"example": [
"live",
"maintenance"
],
"items": {
"type": "string"
}
},
"example": {
"type": "string",
"example": "live"
}
}
},
"status_message": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": ""
}
}
}
}
}
}
},
"DeletedId": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "integer"
},
"example": {
"type": "number",
"example": 12
}
}
}
}
}
}
},
"DeletedSlug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"slug": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "getting-started"
}
}
}
}
}
}
},
"DeletedFlag": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"deleted": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"UnlinkedFlag": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"unlinked": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
},
"UnbanResult": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"properties": {
"type": "object",
"properties": {
"ip": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "203.0.113.5"
}
}
},
"removed": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "boolean"
},
"description": {
"type": "string",
"example": "Whether the IP had an entry that was cleared."
},
"example": {
"type": "boolean",
"example": true
}
}
}
}
}
}
}
}
}
}