openapi: 3.1.0
info:
title: XFEServerManager API
version: 1.0.0
description: |
Server-local management API. All timestamps use RFC 3339 UTC. Mutations are
audited and accept an Idempotency-Key. Long operations return 202 and publish
progress on the SSE event stream. Optional v2 and player-join features report
configured and effective state separately. Runtime-safe feature switches hot-apply;
listener, proxy, executor/session and OpenMetrics initialization changes are
persisted atomically and require a graceful restart. Legacy message fields are
migration inputs only; editable messages live exclusively in trigger groups.
license:
name: MIT
identifier: MIT
servers:
- url: /api/v1
description: Same-origin management API
tags:
- name: auth
description: Owner bootstrap, sessions, TOTP, recent reauthentication and owner-gated account RBAC.
- name: system
description: Process health and lifecycle endpoints.
- name: status
description: Live server performance and population status.
- name: players
description: Online player inspection and safe operations.
- name: policies
description: Versioned command policy validation and publication.
- name: audit
description: Redacted immutable management audit trail.
- name: operations
description: Asynchronous jobs and server-sent events.
- name: console
description: Owner-only Minecraft command console.
- name: moderation
description: Case-based moderation with durable sanctions and revocation.
- name: maintenance
description: Maintenance admission, announcements and structured schedules.
- name: triggers
description: Durable event-condition-action automation with visual and XFE Script editors.
- name: menus
description: Server-authoritative visual UI menus, image assets, submenus and trigger bindings.
- name: economy
description: Exact multi-currency accounts, atomic transfers and an immutable transaction ledger.
- name: claims
description: Persistent claims, membership and boundary protection.
- name: world
description: Persistent world-event lookup.
- name: rollback
description: Previewed, resumable and conflict-aware world rollback.
security:
- sessionCookie: []
paths:
/meta:
get:
summary: Read public API and first-owner setup state
operationId: getApiMetadata
tags: [system]
security: []
responses:
"200":
description: Public control-plane metadata
content:
application/json:
schema:
$ref: "#/components/schemas/ApiMetadata"
default: {$ref: "#/components/responses/Problem"}
/setup:
post:
summary: Create the first owner with a physical-console token
operationId: setupInitialOwner
tags: [auth]
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/SetupRequest"}
responses:
"201":
description: First owner created, token consumed, and session cookie issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/bootstrap:
post:
summary: Deprecated alias for /setup
operationId: bootstrapOwner
tags: [auth]
deprecated: true
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SetupRequest"
responses:
"201":
description: First owner created, token consumed, and session cookie issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/login:
post:
summary: Start an authenticated session
operationId: login
tags: [auth]
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username, password]
properties:
username: {type: string}
password: {type: string, maxLength: 1024}
totp: {type: [string, "null"], pattern: "^[0-9]{6}$"}
recoveryCode: {type: [string, "null"]}
responses:
"200":
description: Session cookie and CSRF token issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
"429":
description: Login or account-wide second-factor attempt limit reached
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/session:
get:
summary: Read the current session or anonymous setup state
operationId: getCurrentSession
tags: [auth]
security: []
responses:
"200":
description: Current browser session state
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/logout:
post:
summary: Revoke the current session
operationId: logout
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Session revoked}
default: {$ref: "#/components/responses/Problem"}
/auth/totp/enrollment:
post:
summary: Begin TOTP enrollment
operationId: beginTotpEnrollment
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [password]
properties:
password: {type: string, maxLength: 1024}
responses:
"200":
description: Unconfirmed TOTP secret and provisioning URI
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: object
required: [secret, provisioningUri, expiresAt]
properties:
secret: {type: string}
provisioningUri: {type: string, format: uri}
expiresAt: {type: string, format: date-time}
default: {$ref: "#/components/responses/Problem"}
/auth/totp/confirm:
post:
summary: Confirm TOTP and issue recovery codes
operationId: confirmTotpEnrollment
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [code]
properties:
code: {type: string, pattern: "^[0-9]{6}$"}
responses:
"200":
description: One-time recovery codes; retrying the same idempotency key repeats only this response
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: object
required: [recoveryCodes]
properties:
recoveryCodes: {type: array, minItems: 8, items: {type: string}}
"429":
description: Three unsuccessful second-factor attempts were made for this account within ten minutes
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/reauthenticate:
post:
summary: Refresh recent-authentication assurance with TOTP
operationId: reauthenticate
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
password:
type: [string, "null"]
maxLength: 1024
description: Optional legacy reauthentication path; the Web UI uses TOTP only.
totp: {type: string, pattern: "^[0-9]{6}$"}
recoveryCode: {type: [string, "null"]}
responses:
"204":
description: The current server-side session now has recent-authentication assurance
"429":
description: Three unsuccessful second-factor attempts were made for this account within ten minutes
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/sessions:
get:
summary: List account sessions
operationId: listSessions
tags: [auth]
responses:
"200":
description: Active sessions with redacted source information
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: array
items: {$ref: "#/components/schemas/Session"}
default: {$ref: "#/components/responses/Problem"}
/auth/sessions/{sessionId}:
delete:
summary: Revoke an account session
operationId: revokeSession
tags: [auth]
parameters:
- name: sessionId
in: path
required: true
schema: {type: string, format: uuid}
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Session revoked or already absent}
default: {$ref: "#/components/responses/Problem"}
/accounts:
get:
summary: List Web management accounts
operationId: listAccounts
tags: [auth]
description: Owner-only. Password hashes, TOTP secrets and recovery codes are never returned.
responses:
"200":
description: Safety-filtered management accounts
content:
application/json:
schema:
type: array
maxItems: 100
items: {$ref: "#/components/schemas/Account"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a Web management account
operationId: createAccount
tags: [auth]
description: Owner-only; requires a TOTP-authenticated session and recent password authentication.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/AccountCreate"}
responses:
"201":
description: Account created
content:
application/json:
schema: {$ref: "#/components/schemas/Account"}
default: {$ref: "#/components/responses/Problem"}
/accounts/{accountId}:
patch:
summary: Change an account role or disabled state
operationId: updateAccount
tags: [auth]
description: Owner-only with TOTP and recent authentication. Demoting or disabling the last owner is rejected atomically and changing an account revokes its existing sessions.
parameters:
- $ref: "#/components/parameters/AccountId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/AccountPatch"}
responses:
"200":
description: Account updated
content:
application/json:
schema: {$ref: "#/components/schemas/Account"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a Web management account
operationId: deleteAccount
tags: [auth]
description: Owner-only with TOTP and recent authentication. Deleting the last owner is rejected atomically.
parameters:
- $ref: "#/components/parameters/AccountId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Account and its sessions deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/healthz:
get:
summary: Read process health
operationId: getHealth
tags: [system]
security: []
servers:
- url: /
responses:
"200":
description: Process health (not authorization readiness)
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Health"
default:
$ref: "#/components/responses/Problem"
/events:
get:
summary: Stream management events
operationId: streamEvents
tags: [operations]
parameters:
- $ref: "#/components/parameters/LastEventId"
responses:
"200":
description: Server-sent events. Event types include status, operation, alert, policy and gap.
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
text/event-stream:
schema:
type: string
default:
$ref: "#/components/responses/Problem"
/status:
get:
summary: Read server status
operationId: getServerStatus
tags: [status]
responses:
"200":
description: Current server status snapshot
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ServerStatus"
default:
$ref: "#/components/responses/Problem"
/features:
get:
summary: Read effective feature availability
operationId: getFeatureFlags
tags: [system]
responses:
"200":
description: Configuration flags intersected with platform capabilities
content:
application/json:
schema: {$ref: "#/components/schemas/FeatureFlags"}
default: {$ref: "#/components/responses/Problem"}
/settings:
get:
summary: Read safety-filtered effective settings
operationId: getSettings
tags: [system]
responses:
"200":
description: Live settings plus any startup-only configuration waiting for restart
content:
application/json:
schema: {$ref: "#/components/schemas/ServerSettings"}
default: {$ref: "#/components/responses/Problem"}
put:
summary: Save editable server settings
operationId: updateSettings
tags: [system]
description: Owner-only. Requires CSRF, TOTP and recent authentication. Runtime-safe fields hot-apply; restartRequired is true only while startup-only fields differ. Legacy message properties are read-only after their one-time trigger migration.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/ServerSettings"}
responses:
"202":
description: Configuration persisted and runtime-safe fields applied
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default: {$ref: "#/components/responses/Problem"}
/triggers:
get:
summary: Read trigger groups and their trigger definitions
operationId: getTriggerWorkspace
tags: [triggers]
responses:
"200":
description: Complete trigger workspace
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a trigger
operationId: createTrigger
tags: [triggers]
description: Administrator or owner with recent TOTP authentication. Arbitrary command actions additionally require the owner-only console capability.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerInput"}
responses:
"202":
description: Trigger created and trigger index refreshed
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerMutationResult"}
default: {$ref: "#/components/responses/Problem"}
/triggers/catalog:
get:
summary: List supported events, conditions, actions, and searchable template variables
operationId: getTriggerCatalog
tags: [triggers]
responses:
"200":
description: Trigger authoring catalog
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerCatalog"}
default: {$ref: "#/components/responses/Problem"}
/triggers/validate:
post:
summary: Validate a visual trigger program or compile and validate XFE Script without saving
operationId: validateTriggerProgram
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
requestBody:
required: true
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/TriggerScriptValidationRequest"
- $ref: "#/components/schemas/TriggerVisualValidationRequest"
responses:
"200":
description: Compiled event-condition-action program
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerValidation"}
default: {$ref: "#/components/responses/Problem"}
/triggers/{triggerId}:
parameters:
- name: triggerId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a trigger with optimistic revision checking
operationId: updateTrigger
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/TriggerInput"
- type: object
required: [expectedRevision]
responses:
"202":
description: Trigger updated and trigger index refreshed
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerMutationResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a trigger
operationId: deleteTrigger
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Trigger deleted
content:
application/json:
schema: {$ref: "#/components/schemas/DeletionResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/trigger-groups:
post:
summary: Create a trigger group
operationId: createTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerGroupInput"}
responses:
"202":
description: Trigger group created
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
default: {$ref: "#/components/responses/Problem"}
/trigger-groups/{groupId}:
parameters:
- name: groupId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a trigger group with optimistic revision checking
operationId: updateTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/TriggerGroupInput"
- type: object
required: [expectedRevision]
responses:
"202":
description: Trigger group updated
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a trigger group and its triggers
operationId: deleteTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Trigger group deleted with all contained triggers
content:
application/json:
schema: {$ref: "#/components/schemas/DeletionResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menus:
get:
summary: List interactive UI menu documents
operationId: listMenus
tags: [menus]
responses:
"200":
description: Menu workspace
content:
application/json:
schema: {$ref: "#/components/schemas/MenuWorkspace"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create an interactive UI menu
operationId: createMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/MenuInput"}
responses:
"202":
description: Menu saved and immediately available to triggers
content:
application/json:
schema: {$ref: "#/components/schemas/MenuSaveResult"}
default: {$ref: "#/components/responses/Problem"}
/menus/catalog:
get:
summary: List menu positions, controls, events and compatible menu.control triggers
operationId: getMenuCatalog
tags: [menus]
responses:
"200":
description: Menu editor catalog
content:
application/json:
schema: {$ref: "#/components/schemas/MenuCatalog"}
default: {$ref: "#/components/responses/Problem"}
/menus/images:
get:
summary: Search uploaded images and vanilla/mod item, block and texture resources
operationId: searchMenuImages
tags: [menus]
parameters:
- name: query
in: query
schema: {type: string, maxLength: 128}
responses:
"200":
description: Bounded image search result
content:
application/json:
schema:
type: object
required: [items, query]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/MenuImage"}}
query: {type: string}
default: {$ref: "#/components/responses/Problem"}
/menus/images/preview:
get:
summary: Resolve an uploaded, vanilla, or installed-mod image reference for browser preview
operationId: getMenuImagePreview
tags: [menus]
parameters:
- name: reference
in: query
required: true
schema:
type: string
maxLength: 256
pattern: '^(uploaded|texture|item|block):'
responses:
"200":
description: Bounded PNG/JPEG preview represented as a data URL
content:
application/json:
schema:
type: object
required: [reference, mimeType, dataUrl]
properties:
reference: {type: string}
mimeType: {type: string, enum: [image/png, image/jpeg]}
dataUrl: {type: string}
"404": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menus/{menuId}:
parameters:
- name: menuId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a menu with optimistic revision checking
operationId: updateMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/MenuInput"
- type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Menu updated
content:
application/json:
schema: {$ref: "#/components/schemas/MenuSaveResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete an unreferenced menu
operationId: deleteMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202": {description: Menu deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets:
post:
summary: Upload a bounded PNG or JPEG menu image
operationId: uploadMenuImage
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, dataUrl]
properties:
name: {type: string, minLength: 1, maxLength: 128}
dataUrl: {type: string, description: Base64 PNG/JPEG data URL; decoded content is limited to 256 KiB.}
responses:
"202":
description: Image stored
content:
application/json:
schema: {$ref: "#/components/schemas/MenuImage"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets/{assetId}:
parameters:
- name: assetId
in: path
required: true
schema: {type: string, format: uuid}
delete:
summary: Delete an image that is not referenced by a menu
operationId: deleteMenuImage
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202": {description: Image deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets/{assetId}/content:
get:
summary: Read one uploaded image as a data URL for the Web editor
operationId: getMenuImageContent
tags: [menus]
parameters:
- name: assetId
in: path
required: true
schema: {type: string, format: uuid}
responses:
"200":
description: Image data
content:
application/json:
schema:
type: object
required: [id, mimeType, dataUrl]
properties:
id: {type: string, format: uuid}
mimeType: {type: string, enum: [image/png, image/jpeg]}
dataUrl: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy:
get:
summary: Read the economy workspace and aggregate overview
operationId: getEconomyWorkspace
tags: [economy]
responses:
"200":
description: Currencies and aggregate metrics
content:
application/json:
schema: {$ref: "#/components/schemas/EconomyWorkspace"}
default: {$ref: "#/components/responses/Problem"}
/economy/currencies:
get:
summary: List every configured currency
operationId: listCurrencies
tags: [economy]
responses:
"200":
description: Currency definitions, primary first
content:
application/json:
schema: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/Currency"}}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a currency
operationId: createCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/CurrencyInput"}
responses:
"202": {description: Currency created and immediately available to accounts and triggers}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/currencies/{currencyId}:
parameters:
- name: currencyId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a currency with optimistic revision checking
operationId: updateCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CurrencyInput"
- type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202": {description: Currency updated}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete an unused non-primary currency
operationId: deleteCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 512}
responses:
"202": {description: Unused currency deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/accounts:
get:
summary: Search player economy accounts
operationId: listEconomyAccounts
tags: [economy]
parameters:
- {name: query, in: query, schema: {type: string, maxLength: 128}}
- {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}
responses:
"200":
description: Economy accounts and all currency balances
content:
application/json:
schema:
type: object
required: [items]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/EconomyAccount"}}
nextCursor: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy/transactions:
get:
summary: Search the immutable economy ledger
operationId: listEconomyTransactions
tags: [economy]
parameters:
- {name: query, in: query, schema: {type: string, maxLength: 128}}
- {name: player, in: query, schema: {type: string}}
- {name: currency, in: query, schema: {type: string}}
- {name: kind, in: query, schema: {type: string, enum: [initial, deposit, withdraw, set, transfer]}}
- {name: before, in: query, schema: {type: string, format: date-time}}
- {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}
responses:
"200":
description: Ledger entries ordered newest first
content:
application/json:
schema:
type: object
required: [items]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/EconomyTransaction"}}
nextCursor: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy/adjustments:
post:
summary: Deposit, withdraw or set one player's exact balance
operationId: adjustEconomyBalance
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [playerId, playerName, currency, operation, amount, reason]
properties:
playerId: {type: string, format: uuid}
playerName: {type: string, minLength: 1, maxLength: 64}
currency: {type: string, description: Currency UUID or code.}
operation: {type: string, enum: [deposit, withdraw, set]}
amount: {$ref: "#/components/schemas/EconomyAmount"}
reason: {type: string, minLength: 1, maxLength: 512}
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Balance changed atomically and ledger entry committed
content: {application/json: {schema: {$ref: "#/components/schemas/EconomyChange"}}}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/transfers:
post:
summary: Atomically transfer currency between two players
operationId: transferEconomyBalance
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sourcePlayerId, sourcePlayerName, targetPlayerId, targetPlayerName, currency, amount, reason]
properties:
sourcePlayerId: {type: string, format: uuid}
sourcePlayerName: {type: string, minLength: 1, maxLength: 64}
targetPlayerId: {type: string, format: uuid}
targetPlayerName: {type: string, minLength: 1, maxLength: 64}
currency: {type: string, description: Currency UUID or code.}
amount: {$ref: "#/components/schemas/EconomyAmount"}
reason: {type: string, minLength: 1, maxLength: 512}
expectedSourceRevision: {type: integer, minimum: 0}
responses:
"202":
description: Both balances and one ledger entry committed in one transaction
content: {application/json: {schema: {$ref: "#/components/schemas/EconomyChange"}}}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/metrics:
get:
summary: Export OpenMetrics
operationId: getMetrics
tags: [status]
servers:
- url: /
security:
- metricsBearer: []
responses:
"200":
description: Token-protected OpenMetrics exposition
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/openmetrics-text:
schema: {type: string}
default: {$ref: "#/components/responses/Problem"}
/players:
get:
summary: List players
operationId: listPlayers
tags: [players]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: online
in: query
schema:
type: boolean
- name: query
in: query
description: Case-insensitive player name or UUID search text.
schema:
type: string
maxLength: 128
responses:
"200":
description: Player page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerPage"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}:
get:
summary: Read player details
operationId: getPlayer
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Player details
headers:
ETag:
description: Player snapshot revision
schema: {type: string}
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerDetail"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/actions:
post:
summary: Preview or execute an online-player action
operationId: executePlayerAction
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerActionRequest"
responses:
"202":
description: Returns PREVIEW_REQUIRED with a frozen target/token, or an accepted/completed operation
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/inventory:
get:
summary: Read an online player's inventory
operationId: getPlayerInventory
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Online player inventory and ender chest revisions
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/InventorySnapshot"
default:
$ref: "#/components/responses/Problem"
patch:
summary: Compare-and-swap inventory slots
operationId: updatePlayerInventory
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/InventoryPatch"
responses:
"202":
description: Audited compare-and-swap result and slot diff
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/InventoryUpdateResult"
"409":
$ref: "#/components/responses/Problem"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/ender-chest:
get:
summary: Read an online player's ender chest
operationId: getPlayerEnderChest
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Ender-chest slots and compare-and-swap revision
content:
application/json:
schema: {$ref: "#/components/schemas/InventorySnapshot"}
default: {$ref: "#/components/responses/Problem"}
patch:
summary: Compare-and-swap ender-chest slots
operationId: updatePlayerEnderChest
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/InventoryPatch"}
responses:
"202":
description: Audited compare-and-swap result and slot diff
content:
application/json:
schema: {$ref: "#/components/schemas/InventoryUpdateResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/policies:
get:
summary: List policy versions
operationId: listPolicies
tags: [policies]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Immutable policy versions
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyPage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Create a policy draft
operationId: createPolicyDraft
tags: [policies]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyDraft"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}:
get:
summary: Read a policy version
operationId: getPolicyVersion
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
responses:
"200":
description: Policy version with validation and diff
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyVersion"
default:
$ref: "#/components/responses/Problem"
delete:
summary: Discard the current unpublished draft
operationId: discardPolicyDraft
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyMutationRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/validate:
post:
summary: Validate a policy draft
operationId: validatePolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200":
description: Validation result; this does not publish the policy
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyValidation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/diff:
get:
summary: Diff a policy version against another revision
operationId: diffPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- name: from
in: query
schema: {type: integer, format: int64, minimum: 0}
responses:
"200":
description: Rule-level immutable version diff
content:
application/json:
schema: {type: object, additionalProperties: true}
default:
$ref: "#/components/responses/Problem"
/policies/simulate:
post:
summary: Simulate policy decisions
operationId: simulatePolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicySimulationRequest"
responses:
"200":
description: Explained active-policy decision without executing the command
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyDecision"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/publish:
post:
summary: Publish a validated policy
operationId: publishPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyPublishRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/rollback:
post:
summary: Restore a historical policy
operationId: rollbackPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyMutationRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/audit:
get:
summary: Search audit events
operationId: listAuditEvents
tags: [audit]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: actor
in: query
schema: {type: string}
- name: action
in: query
schema: {type: string}
- name: query
in: query
deprecated: true
description: Compatibility alias for the action filter.
schema: {type: string}
- name: target
in: query
schema: {type: string}
- name: requestId
in: query
schema: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
- name: from
in: query
schema: {type: string, format: date-time}
- name: to
in: query
schema: {type: string, format: date-time}
responses:
"200":
description: Redacted audit page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/AuditPage"
default:
$ref: "#/components/responses/Problem"
/operations:
post:
summary: Submit a structured player or system operation
operationId: submitOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/OperationRequest"}
responses:
"202":
description: Preview requirement, running job, or completed operation
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default: {$ref: "#/components/responses/Problem"}
/operations/{operationId}:
get:
summary: Read operation status
operationId: getOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/OperationId"
responses:
"200":
description: Operation state and result summary
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Operation"
default:
$ref: "#/components/responses/Problem"
/operations/{operationId}/cancel:
post:
summary: Cancel an operation
operationId: cancelOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Operation tracking or pending preview cancelled
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default:
$ref: "#/components/responses/Problem"
/console/commands:
post:
summary: Execute an owner console command
operationId: executeConsoleCommand
tags: [console]
description: Owner-only and disabled by default. The session must have TOTP assurance and recent password reauthentication.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [command, reason]
properties:
command: {type: string, minLength: 1, maxLength: 4096}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/moderation/cases:
get:
summary: List moderation cases
operationId: listModerationCases
tags: [moderation]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: playerId
in: query
schema: {type: string, format: uuid}
- name: active
in: query
schema: {type: boolean}
responses:
"200":
description: Moderation case page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ModerationCasePage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Open a moderation case
operationId: createModerationCase
tags: [moderation]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateModerationCase"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/moderation/cases/{caseId}/actions/{actionId}/revoke:
post:
summary: Revoke one sanction action in a moderation case
operationId: revokeModerationAction
tags: [moderation]
parameters:
- $ref: "#/components/parameters/CaseId"
- $ref: "#/components/parameters/ActionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Reason"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance:
get:
summary: Read maintenance state
operationId: getMaintenance
tags: [maintenance]
responses:
"200":
description: Maintenance mode and upcoming plans
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceState"
default:
$ref: "#/components/responses/Problem"
put:
summary: Change maintenance state
operationId: setMaintenance
tags: [maintenance]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance/schedules:
post:
summary: Schedule a structured action
operationId: createMaintenanceSchedule
tags: [maintenance]
description: Schedules only structured actions, never arbitrary console commands. Graceful stops announce their target on creation, every five minutes in the final hour, and every second in the final minute.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledAction"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance/announcements:
post:
summary: Broadcast an audited announcement immediately
operationId: announceMaintenanceMessage
tags: [maintenance]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [message, reason]
properties:
message: {type: string, minLength: 1}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Announcement broadcast}
default: {$ref: "#/components/responses/Problem"}
/claims:
get:
summary: List claims
operationId: listClaims
tags: [claims]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: dimension
in: query
schema: {type: string}
- name: ownerId
in: query
schema: {type: string, format: uuid}
responses:
"200":
description: Claim page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ClaimPage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Create a claim
operationId: createClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateClaim"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/claims/{claimId}:
patch:
summary: Update a claim
operationId: updateClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/merge-patch+json:
schema:
$ref: "#/components/schemas/ClaimPatch"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
delete:
summary: Delete a claim using an optimistic revision check
operationId: deleteClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [revision, reason]
properties:
revision: {type: integer, format: int64, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Deleted claim snapshot}
default: {$ref: "#/components/responses/Problem"}
/claims/{claimId}/transfer:
post:
summary: Begin an owner-to-owner claim transfer
operationId: beginClaimTransfer
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [actorId, newOwnerId, reason]
properties:
actorId: {type: string, format: uuid}
newOwnerId: {type: string, format: uuid}
validity: {type: string, default: 10m}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Short-lived single-use transfer ticket}
default: {$ref: "#/components/responses/Problem"}
/claims/transfers/{transferToken}/confirm:
post:
summary: Confirm a claim transfer as its intended recipient
operationId: confirmClaimTransfer
tags: [claims]
parameters:
- name: transferToken
in: path
required: true
schema: {type: string, format: uuid}
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [acceptingPlayerId, reason]
properties:
acceptingPlayerId: {type: string, format: uuid}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Updated claim with its new owner}
default: {$ref: "#/components/responses/Problem"}
/world/changes:
get:
summary: Search world changes
operationId: lookupWorldChanges
tags: [world]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: actorId
in: query
schema: {type: string, format: uuid}
- name: dimension
in: query
schema: {type: string}
- name: x
in: query
schema: {type: integer}
- name: y
in: query
schema: {type: integer}
- name: z
in: query
schema: {type: integer}
- name: radius
in: query
schema: {type: integer, minimum: 0, maximum: 2048}
- name: claimId
in: query
schema: {type: string, format: uuid}
- name: action
in: query
schema: {type: string}
- name: resourceId
in: query
schema: {type: string}
- name: from
in: query
schema: {type: string, format: date-time}
- name: to
in: query
schema: {type: string, format: date-time}
responses:
"200":
description: World event page; gaps are returned explicitly
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/WorldChangePage"
default:
$ref: "#/components/responses/Problem"
/rollbacks/preview:
post:
summary: Preview a rollback
operationId: previewRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RollbackSelection"
responses:
"200":
description: Dry-run fixed to a watermark; does not modify the world
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/RollbackPreview"
default:
$ref: "#/components/responses/Problem"
/rollbacks:
post:
summary: Execute a rollback preview
operationId: executeRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [previewId, confirmationToken, reason]
properties:
previewId: {type: string, format: uuid}
confirmationToken: {type: string}
reason: {type: string, minLength: 1, maxLength: 500}
forceConflicts: {type: boolean, default: false}
loadChunks: {type: boolean, default: false}
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/pause:
post:
summary: Pause a rollback
operationId: pauseRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/resume:
post:
summary: Resume a rollback
operationId: resumeRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/cancel:
post:
summary: Cancel an active rollback after reconciling any in-flight item
operationId: cancelRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200": {description: Cancelled rollback checkpoint}
default: {$ref: "#/components/responses/Problem"}
/rollbacks/{operationId}/redo/preview:
post:
summary: Preview redo of a completed rollback
operationId: previewRedoRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200": {description: Fixed-watermark redo preview}
default:
$ref: "#/components/responses/Problem"
components:
securitySchemes:
sessionCookie:
type: apiKey
in: cookie
name: XFESM_SESSION
metricsBearer:
type: http
scheme: bearer
headers:
RequestId:
description: Correlation ID generated by the server or accepted from a validated request header
schema: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
parameters:
Cursor:
name: cursor
in: query
description: Opaque cursor from the previous page; clients must not parse it.
schema: {type: string}
Limit:
name: limit
in: query
schema: {type: integer, minimum: 1, maximum: 200, default: 50}
LastEventId:
name: Last-Event-ID
in: header
schema: {type: string}
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
description: Unique key for this logical mutation; reuse it when retrying an uncertain response.
schema: {type: string, minLength: 8, maxLength: 128, pattern: "^[A-Za-z0-9._:-]+$"}
CsrfToken:
name: X-CSRF-Token
in: header
required: true
description: Session-bound double-submit token required for same-origin mutations.
schema: {type: string, minLength: 16, maxLength: 256}
PlayerId:
name: playerId
in: path
required: true
schema: {type: string, format: uuid}
AccountId:
name: accountId
in: path
required: true
schema: {type: string, format: uuid}
VersionId:
name: versionId
in: path
required: true
schema: {type: string, pattern: '^policy-[0-9]+$'}
OperationId:
name: operationId
in: path
required: true
schema: {type: string, format: uuid}
CaseId:
name: caseId
in: path
required: true
schema: {type: string, format: uuid}
ActionId:
name: actionId
in: path
required: true
schema: {type: string, format: uuid}
ClaimId:
name: claimId
in: path
required: true
schema: {type: string, format: uuid}
responses:
Problem:
description: RFC 9457 problem details
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
AcceptedOperation:
description: Preview requirement, accepted job, or operation completed within the bounded dispatch window
headers:
Location:
description: Relative operation status URL
schema: {type: string}
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Operation"
schemas:
ApiMetadata:
type: object
required: [name, apiVersion, setupRequired, serverReady]
properties:
name: {type: string}
apiVersion: {type: string, const: v1}
setupRequired: {type: boolean}
serverReady: {type: boolean}
SetupRequest:
type: object
required: [bootstrapToken, username, password]
properties:
bootstrapToken: {type: string, minLength: 16, maxLength: 256}
username: {$ref: "#/components/schemas/AccountUsername"}
password: {type: string, minLength: 12, maxLength: 1024}
Actor:
type: object
required: [id, displayName, roles, permissions, totpEnabled, totpVerified, reauthenticationRequired]
properties:
id: {type: string, format: uuid}
displayName: {type: string}
roles:
type: array
minItems: 1
items: {type: string, enum: [observer, helper, moderator, administrator, owner]}
permissions: {type: array, items: {type: string}}
totpEnabled: {type: boolean}
totpVerified: {type: boolean}
reauthenticationRequired: {type: boolean}
SessionInfo:
type: object
required: [authenticated, bootstrapRequired]
properties:
authenticated: {type: boolean}
actor: {$ref: "#/components/schemas/Actor"}
csrfToken: {type: string}
bootstrapRequired: {type: boolean}
expiresAt: {type: string, format: date-time}
Session:
type: object
required: [id, createdAt, lastSeenAt, expiresAt, current]
properties:
id: {type: string, format: uuid}
createdAt: {type: string, format: date-time}
lastSeenAt: {type: string, format: date-time}
expiresAt: {type: string, format: date-time}
current: {type: boolean}
source: {type: string, description: Redacted source label}
AccountUsername:
type: string
minLength: 3
maxLength: 32
pattern: "^[A-Za-z0-9_.-]+$"
AccountRole:
type: string
enum: [observer, helper, moderator, administrator, owner]
Account:
type: object
required: [id, username, role, totpEnabled, disabled, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
username: {$ref: "#/components/schemas/AccountUsername"}
role: {$ref: "#/components/schemas/AccountRole"}
totpEnabled: {type: boolean}
disabled: {type: boolean}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
lastLoginAt: {type: [string, "null"], format: date-time}
AccountCreate:
type: object
additionalProperties: false
required: [username, password, role]
properties:
username: {$ref: "#/components/schemas/AccountUsername"}
password: {type: string, minLength: 12, maxLength: 1024, writeOnly: true}
role: {$ref: "#/components/schemas/AccountRole"}
AccountPatch:
type: object
additionalProperties: false
minProperties: 1
properties:
role: {$ref: "#/components/schemas/AccountRole"}
disabled: {type: boolean}
Problem:
type: object
required: [type, title, status, detail, requestId]
properties:
type: {type: string, format: uri-reference}
title: {type: string}
status: {type: integer, minimum: 400, maximum: 599}
detail: {type: string}
instance: {type: [string, "null"], format: uri-reference}
requestId: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
extensions: {type: object, additionalProperties: true}
PageMetadata:
type: object
required: [hasMore]
properties:
nextCursor: {type: [string, "null"]}
hasMore: {type: boolean}
Health:
type: object
required: [http, serverReady, sseClients]
properties:
http: {type: string, enum: [running, starting, stopping, stopped, failed]}
serverReady: {type: boolean}
sseClients: {type: integer, minimum: 0}
ServerStatus:
type: object
required: [sampledAt, uptimeSeconds, playersOnline]
properties:
sampledAt: {type: string, format: date-time}
serverName: {type: string}
minecraftVersion: {type: string}
forgeVersion: {type: string}
onlineMode: {type: boolean}
uptimeSeconds: {type: integer, minimum: 0}
tps: {type: number, minimum: 0, maximum: 20}
mspt:
type: object
properties:
average: {type: number, minimum: 0}
p95: {type: number, minimum: 0}
p99: {type: number, minimum: 0}
jitter: {type: number, minimum: 0}
cpuLoad: {type: number, minimum: 0, maximum: 1}
heapUsedBytes: {type: integer, minimum: 0}
heapMaxBytes: {type: integer, minimum: 0}
gcPauseMs: {type: integer, minimum: 0}
diskFreeBytes: {type: integer, minimum: 0}
playersOnline: {type: integer, minimum: 0}
playersMax: {type: integer, minimum: 0}
averagePingMs: {type: number, minimum: 0}
dimensions:
type: array
items:
type: object
properties:
id: {type: string}
loadedChunks: {type: integer, minimum: 0}
entities: {type: integer, minimum: 0}
samples:
type: array
items:
type: object
required: [at]
properties:
at: {type: string, format: date-time}
tps: {type: number, minimum: 0, maximum: 20}
mspt: {type: number, minimum: 0}
FeatureFlags:
type: object
required: [consoleEnabled, moderationEnabled, claimsEnabled, worldTrackingEnabled, rollbackEnabled, joinExperienceEnabled, metricsEnabled]
properties:
consoleEnabled: {type: boolean}
moderationEnabled: {type: boolean}
claimsEnabled: {type: boolean}
worldTrackingEnabled: {type: boolean}
rollbackEnabled: {type: boolean}
joinExperienceEnabled: {type: boolean, description: Legacy compatibility status; authoring moved to triggers.}
metricsEnabled: {type: boolean}
ServerSettings:
type: object
required: [bindAddress, port, trustedProxyCidrs, crashProtection, features, metricsRequireToken, offlineMode, sparkDetected, blueMapDetected]
properties:
bindAddress: {type: string}
port: {type: integer, minimum: 1, maximum: 65535}
trustedProxyCidrs: {type: array, items: {type: string}}
publicBaseUrl: {type: string, format: uri}
idleSessionSeconds: {type: integer, minimum: 1}
absoluteSessionSeconds: {type: integer, minimum: 1}
recentAuthenticationSeconds: {type: integer, minimum: 1}
httpThreads: {type: integer, minimum: 2, maximum: 64}
maximumSseClients: {type: integer, minimum: 1, maximum: 1000}
webConsoleEnabled: {type: boolean}
rawItemEditingEnabled: {type: boolean}
metricsEnabled: {type: boolean}
moderationEnabled: {type: boolean}
claimsEnabled: {type: boolean}
worldTrackingEnabled: {type: boolean}
rollbackEnabled: {type: boolean}
joinExperienceEnabled: {type: boolean, readOnly: true, deprecated: true}
joinWelcomeEnabled: {type: boolean, readOnly: true, deprecated: true}
joinWelcomeMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
firstJoinMessageEnabled: {type: boolean, readOnly: true, deprecated: true}
firstJoinMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
dailyAnnouncementsEnabled: {type: boolean, readOnly: true, deprecated: true}
dailyAnnouncements:
type: array
maxItems: 20
items: {type: string, maxLength: 65536}
readOnly: true
deprecated: true
announcementTimeZone: {type: string, examples: [Asia/Shanghai]}
defaultMessageSender:
type: string
minLength: 1
maxLength: 64
default: XFEServerManager
description: Sender prefix inherited by plain messages and rich messages that do not define an explicit sender. Applied immediately without a restart.
rulesReminderEnabled: {type: boolean, readOnly: true, deprecated: true}
rulesMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
maintenanceJoinReminderEnabled: {type: boolean, readOnly: true, deprecated: true}
crashProtection: {$ref: "#/components/schemas/CrashProtectionSettings"}
restartRequired: {type: boolean}
features: {$ref: "#/components/schemas/FeatureFlags"}
serverLocale: {type: string}
metricsRequireToken: {type: boolean, const: true}
offlineMode: {type: boolean}
sparkDetected: {type: boolean}
blueMapDetected: {type: boolean}
CrashProtectionSettings:
type: object
additionalProperties: false
description: Runtime-safe preemptive limits for entity floods, command-block loops, slow ticks, loaded chunks, and memory pressure. Players and existing living entities are never removed.
required: [enabled, scanIntervalTicks, itemEntitiesPerDimension, itemEntitiesPerChunk, livingEntitiesPerDimension, livingEntitiesPerChunk, totalEntitiesPerDimension, totalEntitiesPerChunk, entitiesPerNamespacePerDimension, loadedChunksPerDimension, spawnBurstLimit, spawnBurstWindowTicks, commandBlockCommandsPerSecond, slowTickMillis, consecutiveSlowTicks, heapUsagePercent, blockExcessSpawns, removeExcessItems, stopRunawayCommandBlocks]
properties:
enabled: {type: boolean, default: true}
scanIntervalTicks: {type: integer, minimum: 20, maximum: 1200, default: 100}
itemEntitiesPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 2000}
itemEntitiesPerChunk: {type: integer, minimum: 1, maximum: 1000000, default: 256}
livingEntitiesPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 2000}
livingEntitiesPerChunk: {type: integer, minimum: 1, maximum: 1000000, default: 128}
totalEntitiesPerDimension: {type: integer, minimum: 1, maximum: 2000000, default: 5000}
totalEntitiesPerChunk: {type: integer, minimum: 1, maximum: 2000000, default: 512}
entitiesPerNamespacePerDimension: {type: integer, minimum: 1, maximum: 2000000, default: 512}
loadedChunksPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 8000}
spawnBurstLimit: {type: integer, minimum: 1, maximum: 1000000, default: 400}
spawnBurstWindowTicks: {type: integer, minimum: 20, maximum: 72000, default: 100}
commandBlockCommandsPerSecond: {type: integer, minimum: 1, maximum: 100000, default: 100}
slowTickMillis: {type: integer, minimum: 50, maximum: 60000, default: 200}
consecutiveSlowTicks: {type: integer, minimum: 1, maximum: 1200, default: 3}
heapUsagePercent: {type: integer, minimum: 50, maximum: 99, default: 90}
blockExcessSpawns: {type: boolean, default: true}
removeExcessItems: {type: boolean, default: true}
stopRunawayCommandBlocks: {type: boolean, default: true}
PlayerSummary:
type: object
required: [uuid, name, online]
properties:
uuid: {type: string, format: uuid}
name: {type: string}
online: {type: boolean}
pingMs: {type: integer, minimum: 0}
roles: {type: array, items: {type: string}}
opLevel: {type: integer, minimum: 0, maximum: 4}
gameMode: {type: string}
health: {type: number, minimum: 0}
foodLevel: {type: integer, minimum: 0}
location:
allOf:
- $ref: "#/components/schemas/Position"
- type: object
required: [dimension]
properties:
dimension: {type: string}
PlayerDetail:
allOf:
- $ref: "#/components/schemas/PlayerSummary"
- type: object
properties:
connectedAt: {type: string, format: date-time}
PlayerPage:
type: object
required: [items]
properties:
items: {type: array, items: {$ref: "#/components/schemas/PlayerSummary"}}
nextCursor: {type: string}
Position:
type: object
required: [x, y, z]
properties:
x: {type: number}
y: {type: number}
z: {type: number}
Reason:
type: object
required: [reason]
properties:
reason: {type: string, minLength: 1, maxLength: 500}
PlayerActionRequest:
type: object
required: [action, reason]
properties:
action:
type: string
enum: [message, kick, teleport, recall, heal, feed, gamemode, clear_effects, whitelist, ban]
reason: {type: string, minLength: 1, maxLength: 500}
value: {type: string}
confirmedTargetUuid:
type: string
format: uuid
deprecated: true
description: Optional UI cross-check; the path and frozen preview UUID are authoritative.
previewToken: {type: string, format: uuid}
ItemStack:
type: object
required: [slot, itemId, count, structuredData, opaqueDataPresent, opaqueDataFingerprint]
properties:
slot: {type: integer, minimum: 0}
itemId: {type: string}
count: {type: integer, minimum: 0}
structuredData: {type: object, additionalProperties: {type: string}}
opaqueDataPresent:
type: boolean
readOnly: true
description: True when server-side NBT/data components exist but are deliberately redacted.
opaqueDataFingerprint:
type: string
readOnly: true
pattern: "^([0-9a-f]{64})?$"
description: Non-reversible change marker; never a restorable raw payload.
ItemStackPatch:
type: object
additionalProperties: false
required: [slot, itemId, count, structuredData]
properties:
slot: {type: integer, minimum: 0}
itemId: {type: string}
count: {type: integer, minimum: 0, maximum: 127}
structuredData: {type: object, additionalProperties: {type: string}}
InventorySnapshot:
type: object
required: [playerUuid, container, revision, online, slots]
properties:
playerUuid: {type: string, format: uuid}
container: {type: string, enum: [inventory, ender_chest]}
revision: {type: integer, minimum: 0}
online: {type: boolean}
slots: {type: array, items: {$ref: "#/components/schemas/ItemStack"}}
InventoryPatch:
type: object
required: [expectedRevision, updates, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
updates:
type: array
minItems: 1
items:
$ref: "#/components/schemas/ItemStackPatch"
reason: {type: string, minLength: 1, maxLength: 500}
rawEditingRequested: {type: boolean, default: false}
InventorySlotDiff:
type: object
required: [slot, before, after]
properties:
slot: {type: integer, minimum: 0}
before: {$ref: "#/components/schemas/ItemStack"}
after: {$ref: "#/components/schemas/ItemStack"}
InventoryUpdateResult:
allOf:
- $ref: "#/components/schemas/Operation"
- type: object
required: [revision, diffs]
properties:
revision: {type: integer, format: int64, minimum: 0}
diffs:
type: array
items: {$ref: "#/components/schemas/InventorySlotDiff"}
PolicyDraft:
type: object
required: [expectedActiveVersion, description, rules]
properties:
expectedActiveVersion: {type: integer, format: int64, minimum: 0}
description: {type: string, minLength: 1, maxLength: 1000}
rules: {type: array, items: {type: object, additionalProperties: true}}
PolicyPublishRequest:
type: object
required: [version, reason]
properties:
version: {type: integer, format: int64, minimum: 1}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyMutationRequest:
type: object
required: [expectedActiveVersion, reason]
properties:
expectedActiveVersion: {type: integer, format: int64, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyVersion:
type: object
required: [id, version, name, state, groupCount, ruleCount, updatedAt]
properties:
id: {type: string, pattern: '^policy-[0-9]+$'}
version: {type: integer, format: int64, minimum: 0}
name: {type: string}
description: {type: string}
state: {type: string, enum: [DRAFT, ACTIVE, ARCHIVED]}
groupCount: {type: integer, minimum: 0}
ruleCount: {type: integer, minimum: 0}
updatedAt: {type: string, format: date-time}
updatedBy: {type: string}
checksum: {type: string}
rules:
type: array
items:
allOf:
- $ref: "#/components/schemas/PolicyRule"
validation: {$ref: "#/components/schemas/PolicyValidation"}
PolicyRule:
type: object
required: [id, enabled, groupId, groupName, groupEnabled, tier, subject, command, effect, constraints, reason]
properties:
id: {type: string, pattern: '^[A-Za-z0-9._-]+$'}
enabled: {type: boolean}
groupId: {type: string, pattern: '^[A-Za-z0-9._-]{1,64}$'}
groupName: {type: string, minLength: 1, maxLength: 128}
groupEnabled: {type: boolean}
tier: {type: string, enum: [DEFAULT, OP_LEVEL, ROLE, UUID, HARD_SAFETY]}
subject: {type: object, additionalProperties: true}
command: {type: object, additionalProperties: true}
effect: {type: string, enum: [PASS_THROUGH, DENY, GRANT, CONSTRAIN]}
constraints: {type: object, additionalProperties: true}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyPage:
type: object
required: [items, nextCursor]
properties:
items: {type: array, items: {$ref: "#/components/schemas/PolicyVersion"}}
nextCursor: {type: [string, "null"]}
PolicyValidation:
type: object
required: [valid, errors, warnings]
properties:
valid: {type: boolean}
errors:
type: array
items: {$ref: "#/components/schemas/PolicyValidationIssue"}
warnings:
type: array
items: {$ref: "#/components/schemas/PolicyValidationIssue"}
PolicyValidationIssue:
type: object
required: [ruleId, code, message]
properties:
ruleId: {type: string}
code: {type: string}
message: {type: string}
PolicySimulationRequest:
type: object
required: [command]
properties:
command: {type: string, minLength: 1, maxLength: 4096}
playerUuid: {type: [string, "null"], format: uuid}
PolicyDecision:
type: object
required: [decision, explanation, matchedRuleIds, normalizedCommand]
properties:
decision: {type: string, enum: [PASS_THROUGH, DENY, GRANT, CONSTRAIN]}
explanation: {type: array, items: {type: string}}
matchedRuleIds: {type: array, items: {type: string}}
normalizedCommand: {type: string}
AuditEvent:
type: object
required: [id, at, actor, source, action, result]
properties:
id: {type: string, format: uuid}
at: {type: string, format: date-time}
actor: {type: string}
source: {type: string}
target: {type: [string, "null"]}
action: {type: string}
reason: {type: [string, "null"]}
requestId: {type: string}
result: {type: string}
durationMs: {type: integer, minimum: 0}
AuditPage:
type: object
required: [items, nextCursor]
properties:
items: {type: array, items: {$ref: "#/components/schemas/AuditEvent"}}
nextCursor: {type: [string, "null"]}
OperationRequest:
type: object
required: [action, reason]
properties:
action: {type: string}
target: {}
reason: {type: string, minLength: 1, maxLength: 512}
parameters: {type: object, additionalProperties: true}
previewToken: {type: string, format: uuid}
Operation:
type: object
required: [id, kind, state]
properties:
id: {type: string, format: uuid}
kind: {type: string}
state: {type: string, enum: [PREVIEW_REQUIRED, QUEUED, RUNNING, PAUSED, SUCCEEDED, PARTIAL, FAILED, CANCELLED]}
createdAt: {type: string, format: date-time}
completedAt: {type: string, format: date-time}
expiresAt: {type: string, format: date-time}
progress: {type: number, minimum: 0, maximum: 1}
message: {type: string}
requestId: {type: string}
previewToken: {type: string, format: uuid}
targets:
type: array
items:
type: object
required: [uuid]
properties:
uuid: {type: string, format: uuid}
name: {type: string}
result:
oneOf:
- {type: object, additionalProperties: true}
- {type: integer}
results: {type: array, items: {type: object, additionalProperties: true}}
revision: {type: integer, minimum: 0}
diffs: {type: array, items: {type: object, additionalProperties: true}}
error: {$ref: "#/components/schemas/Problem"}
CreateModerationCase:
type: object
required: [playerId, action, reason]
properties:
playerId: {type: string, format: uuid}
action: {type: string, enum: [warn, mute, kick, tempban, ban]}
reason: {type: string, minLength: 1, maxLength: 500}
message: {type: string, minLength: 1, maxLength: 500, description: Player-facing message; defaults to reason when omitted.}
duration: {type: string, description: "Required for tempban. Examples include 30m, 2h, 7d, or an ISO-8601 duration."}
templateId: {type: [string, "null"]}
expiresAt: {type: [string, "null"], format: date-time}
evidenceUrls: {type: array, items: {type: string, format: uri}}
staffNote: {type: string, maxLength: 4000}
ModerationCase:
type: object
required: [id, playerId, action, reason, createdAt, active]
properties:
id: {type: string, format: uuid}
playerId: {type: string, format: uuid}
action: {type: string}
reason: {type: string}
message: {type: string}
createdAt: {type: string, format: date-time}
expiresAt: {type: [string, "null"], format: date-time}
active: {type: boolean}
remainingSeconds: {type: integer, description: "Seconds remaining, or -1 for a permanent/no-expiry action."}
evidenceUrls: {type: array, items: {type: string, format: uri}}
ModerationCasePage:
type: object
required: [items, page]
properties:
items: {type: array, items: {$ref: "#/components/schemas/ModerationCase"}}
page: {$ref: "#/components/schemas/PageMetadata"}
MaintenanceState:
type: object
required: [enabled, whitelistOnly, schedules, defaultMessageSender]
properties:
enabled: {type: boolean}
whitelistOnly: {type: boolean}
message: {type: string}
defaultMessageSender: {type: string, minLength: 1, maxLength: 64}
endsAt: {type: [string, "null"], format: date-time}
schedules: {type: array, items: {$ref: "#/components/schemas/ScheduledAction"}}
MaintenanceRequest:
type: object
required: [enabled, reason]
properties:
enabled: {type: boolean}
whitelistOnly: {type: boolean, default: true}
message: {type: string, maxLength: 500}
endsAt: {type: [string, "null"], format: date-time}
countdownSeconds: {type: integer, minimum: 0, maximum: 86400}
reason: {type: string, minLength: 1, maxLength: 500}
ScheduledAction:
type: object
required: [kind, executeAt, reason]
properties:
id: {type: string, format: uuid, readOnly: true}
kind: {type: string, enum: [announce, enable_maintenance, disable_maintenance, save_flush, graceful_stop]}
executeAt: {type: string, format: date-time}
arguments: {type: object, additionalProperties: true}
reason: {type: string, minLength: 1, maxLength: 500}
status: {type: string, enum: [PENDING, CLAIMED, COMPLETED, CANCELLED], readOnly: true}
attempts: {type: integer, minimum: 0, readOnly: true}
leaseUntil: {type: [string, "null"], format: date-time, readOnly: true}
completedAt: {type: [string, "null"], format: date-time, readOnly: true}
lastError: {type: string, readOnly: true}
createdBy: {type: string, readOnly: true}
TriggerWorkspace:
type: object
required: [groups, totalTriggers]
properties:
groups:
type: array
maxItems: 256
items: {$ref: "#/components/schemas/TriggerGroup"}
totalTriggers: {type: integer, minimum: 0, maximum: 1024}
TriggerCatalog:
type: object
required: [events, operators, actions, actionParameters, variables, variableSyntax, defaultMessageSender]
properties:
events: {type: array, items: {type: string}}
operators: {type: array, items: {type: string}}
actions: {type: array, items: {type: string}}
actionParameters:
type: object
additionalProperties:
type: array
items: {type: string}
variables:
type: array
minItems: 100
items: {$ref: "#/components/schemas/TriggerVariableDefinition"}
variableSyntax:
$ref: "#/components/schemas/TriggerVariableSyntax"
defaultMessageSender: {type: string, minLength: 1, maxLength: 64}
TriggerVariableDefinition:
type: object
required: [key, nameZh, nameEn, descriptionZh, descriptionEn, category, scopes,
example, sampleValue, formatHint, type, events, templateAllowed, conditionAllowed]
properties:
key:
type: string
description: Variable expression without the surrounding braces
nameZh: {type: string}
nameEn: {type: string}
descriptionZh: {type: string}
descriptionEn: {type: string}
category: {type: string}
scopes:
type: array
minItems: 1
items: {type: string}
description: Semantic UI scopes such as global, player-event, world, command, or schedule
example:
type: string
description: Complete placeholder ready for insertion
sampleValue:
type: string
description: Example resolved value, or an empty string when no fixed sample is useful
formatHint: {type: string}
type: {type: string, enum: [string, number, boolean, instant, datetime]}
events:
type: array
minItems: 1
items: {type: string}
description: Exact event IDs or bounded glob patterns; `*` means every event
templateAllowed: {type: boolean}
conditionAllowed: {type: boolean}
TriggerVariableSyntax:
type: object
required: [delimiter, formattedTime, formatHint]
properties:
delimiter: {type: string, example: "{variable}"}
formattedTime: {type: string, example: "{server.time:uuuu-MM-dd HH:mm:ss}"}
formatHint: {type: string}
TriggerMutationResult:
type: object
required: [trigger, workspace]
properties:
trigger: {$ref: "#/components/schemas/Trigger"}
workspace: {$ref: "#/components/schemas/TriggerWorkspace"}
TriggerValidation:
type: object
required: [valid, event, conditionMode, conditions, actions]
properties:
valid: {type: boolean, const: true}
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
TriggerScriptValidationRequest:
type: object
additionalProperties: false
required: [script]
properties:
script: {type: string, minLength: 1, maxLength: 65536}
TriggerVisualValidationRequest:
type: object
additionalProperties: false
required: [event, conditionMode, conditions, actions]
properties:
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
DeletionResult:
type: object
required: [deleted, id]
properties:
deleted: {type: boolean, const: true}
id: {type: string, format: uuid}
TriggerGroup:
allOf:
- $ref: "#/components/schemas/TriggerGroupInput"
- type: object
required: [id, revision, triggers, createdBy, createdAt, updatedAt, migrated]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
triggers: {type: array, maxItems: 256, items: {$ref: "#/components/schemas/Trigger"}}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
migrated: {type: boolean}
TriggerGroupInput:
type: object
required: [name, enabled]
properties:
name: {type: string, minLength: 1, maxLength: 120}
description: {type: string, maxLength: 500}
enabled: {type: boolean}
expectedRevision: {type: integer, minimum: 0}
Trigger:
allOf:
- $ref: "#/components/schemas/TriggerInput"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt, migrated]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
migrated: {type: boolean}
TriggerInput:
type: object
required: [groupId, name, enabled, mode]
properties:
groupId: {type: string, format: uuid}
name: {type: string, minLength: 1, maxLength: 120}
description: {type: string, maxLength: 500}
enabled: {type: boolean}
mode: {type: string, enum: [visual, code]}
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
script: {type: string, maxLength: 65536}
expectedRevision: {type: integer, minimum: 0}
oneOf:
- title: Visual trigger
required: [event, conditionMode, conditions, actions]
properties:
mode: {const: visual}
- title: XFE Script trigger
required: [script]
properties:
mode: {const: code}
TriggerEvent:
type: object
required: [type, configuration]
properties:
type: {type: string, minLength: 1, maxLength: 80}
configuration:
type: object
maxProperties: 16
description: schedule.daily uses time and timezone. schedule.interval accepts legacy total seconds or hours/minutes/seconds components, normalizes them to total seconds (1..31536000), and aligns execution to server-local wall-clock boundaries. player.command_trigger uses command plus an optional legacy whitespace-separated arguments declaration. protection.* events use threshold and cooldownSeconds; count-based item/mob/entity events also accept scope=dimension|chunk, mod_entity_overflow accepts namespace, and slow_tick accepts consecutive.
additionalProperties: {type: string, maxLength: 4096}
arguments:
type: array
description: Recursive Brigadier alternatives for player.command_trigger. Siblings are alternatives and children form the next input level.
items: {$ref: "#/components/schemas/TriggerCommandArgument"}
variables:
type: array
description: Strongly typed trigger-local or server-global state declarations. Missing visibility/storage fields migrate as trigger-local trigger storage.
items: {$ref: "#/components/schemas/TriggerStateVariable"}
TriggerCommandArgument:
type: object
required: [name, type, literal, optional, errorMessage, minimum, maximum, suggestions, children]
properties:
name: {type: string, pattern: '^[a-z][a-z0-9_-]{0,31}$'}
type: {type: string, description: A supported vanilla Brigadier argument family or literal.}
literal: {type: string, maxLength: 128}
optional: {type: boolean}
errorMessage: {type: string, maxLength: 256}
minimum: {type: string}
maximum: {type: string}
suggestions: {type: array, maxItems: 64, items: {type: string, minLength: 1, maxLength: 128}}
children: {type: array, items: {$ref: "#/components/schemas/TriggerCommandArgument"}}
TriggerStateVariable:
type: object
required: [name, type, initialValue]
properties:
name: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_-]{0,47}$'}
type:
type: string
description: Scalar type, legacy list, or recursively nested array<T>/dictionary<K,V>; dictionary keys must be scalar.
initialValue:
type: string
maxLength: 65536
description: Scalars use their text form; arrays and dictionaries use strictly typed JSON.
visibility: {type: string, enum: [trigger, global], default: trigger}
storage:
type: string
enum: [server, player, dimension, trigger]
description: Selects one shared value, a value per triggering player, per dimension, or per executing trigger.
TriggerCondition:
type: object
required: [field, operator, value]
properties:
field: {type: string, minLength: 1, maxLength: 120}
operator: {type: string, enum: [eq, neq, contains, not_contains, starts_with, not_starts_with, ends_with, not_ends_with, matches, not_matches, gt, gte, lt, lte, between, not_between, in, not_in, empty, not_empty, 'true', 'false', exists, not_exists]}
value: {type: string, maxLength: 4096}
TriggerAction:
type: object
required: [type, parameters]
description: An executable action, or a structural condition whose children run only when its field/operator/value passes. Only condition nodes may have children; authoring does not impose an artificial node-count or nesting-depth limit.
properties:
type: {type: string, enum: [condition, send_player, broadcast, title, actionbar, sound, server_command, player_command, kick, teleport, give_item, clear_inventory, set_gamemode, add_effect, remove_effects, heal, feed, set_time, set_weather, whitelist_add, whitelist_remove, ban, pardon, log, variable, wait, run_trigger, open_menu, close_menu, economy_deposit, economy_withdraw, economy_set_balance, economy_transfer, economy_deposit_player, economy_withdraw_player, economy_set_player_balance, economy_transfer_players]}
parameters:
type: object
maxProperties: 16
description: Condition nodes use field, operator, and value. Command actions accept showFeedback=true|false and default to false. Rich message envelopes are limited to 256 segments and 8192 visible characters and are validated on save.
additionalProperties: {type: string, maxLength: 65536}
children:
type: array
description: Non-empty for condition nodes; omitted or empty for executable actions.
items: {$ref: "#/components/schemas/TriggerAction"}
MenuWorkspace:
type: object
required: [menus, totalMenus]
properties:
menus: {type: array, maxItems: 512, items: {$ref: "#/components/schemas/Menu"}}
totalMenus: {type: integer, minimum: 0, maximum: 512}
MenuSaveResult:
type: object
required: [menu, workspace]
properties:
menu: {$ref: "#/components/schemas/Menu"}
workspace: {$ref: "#/components/schemas/MenuWorkspace"}
Menu:
allOf:
- $ref: "#/components/schemas/MenuInput"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
MenuInput:
type: object
required: [name, width, height, popupPosition, backgroundColor, controls]
properties:
name: {type: string, minLength: 1, maxLength: 96}
description: {type: string, maxLength: 1024}
width: {type: integer, minimum: 120, maximum: 1920}
height: {type: integer, minimum: 80, maximum: 1080}
popupPosition: {type: string, enum: [center, top, bottom, left, right, top_left, top_right, bottom_left, bottom_right, custom]}
offsetX: {type: integer, minimum: -8192, maximum: 8192}
offsetY: {type: integer, minimum: -8192, maximum: 8192}
pauseGame: {type: boolean, default: false}
backgroundColor: {type: string, pattern: '^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$'}
controls: {type: array, maxItems: 128, items: {$ref: "#/components/schemas/MenuControl"}}
MenuControl:
type: object
required: [id, type, x, y, width, height, zIndex, visibleWhen, properties, events]
properties:
id: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_.-]{0,63}$'}
type: {type: string, enum: [text, rich_text, button, icon_button, image, panel, border, progress, input, checkbox, slider, item_slot, separator, spacer]}
x: {type: integer, minimum: 0}
y: {type: integer, minimum: 0}
width: {type: integer, minimum: 1, maximum: 1920}
height: {type: integer, minimum: 1, maximum: 1080}
zIndex: {type: integer, minimum: -1000, maximum: 1000}
visibleWhen: {type: string, maxLength: 512}
properties:
type: object
maxProperties: 48
additionalProperties: {type: string, maxLength: 16384}
events: {type: array, maxItems: 8, items: {$ref: "#/components/schemas/MenuControlEvent"}}
MenuControlEvent:
type: object
required: [event, triggerId, submenuId, closeMenu]
properties:
event: {type: string, enum: [click, double_click, change, submit, toggle, hover, focus, blur]}
triggerId: {type: string, description: "Empty, or UUID of a menu.control trigger."}
submenuId: {type: string, description: "Empty, or UUID of an existing acyclic submenu."}
closeMenu: {type: boolean}
MenuCatalog:
type: object
required: [controlTypes, popupPositions, controlEvents, triggers]
properties:
controlTypes: {type: array, items: {type: string}}
popupPositions: {type: array, items: {type: string}}
controlEvents: {type: array, items: {type: string}}
triggers:
type: array
items:
type: object
required: [id, name, enabled]
properties:
id: {type: string, format: uuid}
name: {type: string}
enabled: {type: boolean}
MenuImage:
type: object
required: [reference, name, type, source]
properties:
id: {type: string, format: uuid}
reference: {type: string, description: 'uploaded:, texture:, item:, or block: reference.'}
name: {type: string}
type: {type: string, enum: [uploaded, texture, item, block]}
source: {type: string}
mimeType: {type: string, enum: [image/png, image/jpeg]}
width: {type: integer, minimum: 1, maximum: 1024}
height: {type: integer, minimum: 1, maximum: 1024}
sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
dataUrl: {type: string}
EconomyAmount:
type: string
pattern: '^-?(0|[1-9][0-9]*)(\.[0-9]+)?$'
description: Exact base-10 amount. Floating-point JSON numbers are intentionally not accepted.
CurrencyFields:
type: object
required: [code, name, symbol, icon, fractionDigits, initialBalance, minimumBalance, maximumBalance, playerTransferAllowed, enabled, primary]
properties:
code: {type: string, pattern: '^[a-z][a-z0-9_]{0,31}$'}
name: {type: string, minLength: 1, maxLength: 64}
symbol: {type: string, minLength: 1, maxLength: 16}
icon: {type: string, description: 'uploaded:, texture:, item:, or block: reference.'}
fractionDigits: {type: integer, minimum: 0, maximum: 6}
initialBalance: {$ref: "#/components/schemas/EconomyAmount"}
minimumBalance: {$ref: "#/components/schemas/EconomyAmount"}
maximumBalance: {$ref: "#/components/schemas/EconomyAmount"}
playerTransferAllowed: {type: boolean, description: Allows player-initiated command payments; audited management and trigger transfers remain available.}
enabled: {type: boolean}
primary: {type: boolean}
CurrencyInput:
allOf:
- $ref: "#/components/schemas/CurrencyFields"
- type: object
required: [reason]
properties:
reason: {type: string, minLength: 1, maxLength: 512}
Currency:
allOf:
- $ref: "#/components/schemas/CurrencyFields"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
EconomyBalance:
type: object
required: [currencyId, currencyCode, currencyName, symbol, icon, fractionDigits, amount, revision, currencyEnabled, updatedAt]
properties:
currencyId: {type: string, format: uuid}
currencyCode: {type: string}
currencyName: {type: string}
symbol: {type: string}
icon: {type: string}
fractionDigits: {type: integer, minimum: 0, maximum: 6}
amount: {$ref: "#/components/schemas/EconomyAmount"}
revision: {type: integer, minimum: 0}
currencyEnabled: {type: boolean}
updatedAt: {type: string, format: date-time}
EconomyAccount:
type: object
required: [playerId, playerName, balances, updatedAt]
properties:
playerId: {type: string, format: uuid}
playerName: {type: string}
balances: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/EconomyBalance"}}
updatedAt: {type: string, format: date-time}
EconomyTransaction:
type: object
required: [id, currencyId, currencyCode, kind, sourcePlayerName, targetPlayerName, amount, sourceBalanceBefore, sourceBalanceAfter, targetBalanceBefore, targetBalanceAfter, reason, actor, origin, correlationId, createdAt]
properties:
id: {type: string, format: uuid}
currencyId: {type: string, format: uuid}
currencyCode: {type: string}
kind: {type: string, enum: [initial, deposit, withdraw, set, transfer]}
sourcePlayerId: {type: string, format: uuid}
sourcePlayerName: {type: string}
targetPlayerId: {type: string, format: uuid}
targetPlayerName: {type: string}
amount: {$ref: "#/components/schemas/EconomyAmount"}
sourceBalanceBefore: {type: string}
sourceBalanceAfter: {type: string}
targetBalanceBefore: {type: string}
targetBalanceAfter: {type: string}
reason: {type: string}
actor: {type: string}
origin: {type: string, enum: [system, web, command, trigger]}
correlationId: {type: string}
createdAt: {type: string, format: date-time}
EconomyCurrencySummary:
type: object
required: [currencyId, code, name, symbol, icon, fractionDigits, enabled, primary, accountCount, totalSupply, minimumBalance, maximumBalance, transactionCount, transferVolume24h]
properties:
currencyId: {type: string, format: uuid}
code: {type: string}
name: {type: string}
symbol: {type: string}
icon: {type: string}
fractionDigits: {type: integer}
enabled: {type: boolean}
primary: {type: boolean}
accountCount: {type: integer, minimum: 0}
totalSupply: {$ref: "#/components/schemas/EconomyAmount"}
minimumBalance: {$ref: "#/components/schemas/EconomyAmount"}
maximumBalance: {$ref: "#/components/schemas/EconomyAmount"}
transactionCount: {type: integer, minimum: 0}
transferVolume24h: {$ref: "#/components/schemas/EconomyAmount"}
EconomyWorkspace:
type: object
required: [currencies, overview]
properties:
currencies: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/Currency"}}
overview:
type: object
required: [currencies, observedAt]
properties:
currencies: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/EconomyCurrencySummary"}}
observedAt: {type: string, format: date-time}
EconomyChange:
type: object
required: [currency, transaction]
properties:
currency: {$ref: "#/components/schemas/Currency"}
transaction: {$ref: "#/components/schemas/EconomyTransaction"}
sourceBalance: {$ref: "#/components/schemas/EconomyBalance"}
targetBalance: {$ref: "#/components/schemas/EconomyBalance"}
ChunkPosition:
type: object
required: [x, z]
properties:
x: {type: integer}
z: {type: integer}
Claim:
type: object
required: [id, dimension, ownerId, chunks, members, flags, revision]
properties:
id: {type: string, format: uuid}
name: {type: string}
dimension: {type: string}
ownerId: {type: string, format: uuid}
chunks: {type: array, items: {$ref: "#/components/schemas/ChunkPosition"}}
members:
type: object
additionalProperties: {type: string, enum: [manager, member, trusted]}
flags:
type: object
additionalProperties: {type: boolean}
revision: {type: integer, minimum: 0}
CreateClaim:
type: object
required: [name, dimension, chunks]
properties:
name: {type: string, minLength: 1, maxLength: 64}
dimension: {type: string}
chunks: {type: array, minItems: 1, items: {$ref: "#/components/schemas/ChunkPosition"}}
adminOverride: {type: boolean, default: false}
ClaimPatch:
type: object
required: [expectedRevision, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
name: {type: string, minLength: 1, maxLength: 64}
chunks: {type: array, minItems: 1, items: {$ref: "#/components/schemas/ChunkPosition"}}
members: {type: object, additionalProperties: {type: string}}
flags: {type: object, additionalProperties: {type: boolean}}
transferTo: {type: string, format: uuid}
transferConfirmation: {type: string}
reason: {type: string, minLength: 1, maxLength: 500}
ClaimPage:
type: object
required: [items, page]
properties:
items: {type: array, items: {$ref: "#/components/schemas/Claim"}}
page: {$ref: "#/components/schemas/PageMetadata"}
WorldChange:
type: object
required: [id, timestamp, tick, dimension, position, action, resourceId, restorable]
properties:
id: {type: string, format: uuid}
timestamp: {type: string, format: date-time}
tick: {type: integer}
dimension: {type: string}
position: {$ref: "#/components/schemas/Position"}
actorId: {type: [string, "null"], format: uuid}
cause: {type: string}
action: {type: string}
resourceId: {type: string}
modFingerprint: {type: [string, "null"]}
restorable: {type: boolean}
incompatibility: {type: [string, "null"]}
transactionId: {type: string, format: uuid}
WorldChangePage:
type: object
required: [items, page, gaps]
properties:
items: {type: array, items: {$ref: "#/components/schemas/WorldChange"}}
page: {$ref: "#/components/schemas/PageMetadata"}
gaps:
type: array
items:
type: object
properties:
from: {type: string, format: date-time}
to: {type: string, format: date-time}
reason: {type: string}
RollbackSelection:
type: object
required: [from, to, reason]
properties:
from: {type: string, format: date-time}
to: {type: string, format: date-time}
actorId: {type: [string, "null"], format: uuid}
dimension: {type: [string, "null"]}
center: {$ref: "#/components/schemas/Position"}
radius: {type: integer, minimum: 0, maximum: 2048}
claimId: {type: [string, "null"], format: uuid}
actions: {type: array, items: {type: string}}
includeEntitiesAndItems: {type: boolean, default: false}
reason: {type: string, minLength: 1, maxLength: 500}
RollbackPreview:
type: object
required: [id, watermark, expiresAt, selected, applicable, conflicts, unloadedChunks, gaps, incompatible, confirmationToken]
properties:
id: {type: string, format: uuid}
watermark: {type: integer, format: int64, minimum: 0}
expiresAt: {type: string, format: date-time}
selected: {type: integer, minimum: 0}
applicable: {type: integer, minimum: 0}
conflicts: {type: integer, minimum: 0}
unloadedChunks: {type: integer, minimum: 0}
gaps: {type: integer, minimum: 0}
incompatible: {type: integer, minimum: 0}
estimatedChunkLoads: {type: integer, minimum: 0, maximum: 128}
confirmationToken: {type: string}
openapi: 3.1.0
info:
title: XFEServerManager API
version: 1.0.0
description: |
Server-local management API. All timestamps use RFC 3339 UTC. Mutations are
audited and accept an Idempotency-Key. Long operations return 202 and publish
progress on the SSE event stream. Optional v2 and player-join features report
configured and effective state separately. Runtime-safe feature switches hot-apply;
listener, proxy, executor/session and OpenMetrics initialization changes are
persisted atomically and require a graceful restart. Legacy message fields are
migration inputs only; editable messages live exclusively in trigger groups.
license:
name: MIT
identifier: MIT
servers:
- url: /api/v1
description: Same-origin management API
tags:
- name: auth
description: Owner bootstrap, sessions, TOTP, recent reauthentication and owner-gated account RBAC.
- name: system
description: Process health and lifecycle endpoints.
- name: status
description: Live server performance and population status.
- name: players
description: Online player inspection and safe operations.
- name: policies
description: Versioned command policy validation and publication.
- name: audit
description: Redacted immutable management audit trail.
- name: operations
description: Asynchronous jobs and server-sent events.
- name: console
description: Owner-only Minecraft command console.
- name: moderation
description: Case-based moderation with durable sanctions and revocation.
- name: maintenance
description: Maintenance admission, announcements and structured schedules.
- name: triggers
description: Durable event-condition-action automation with visual and XFE Script editors.
- name: menus
description: Server-authoritative visual UI menus, image assets, submenus and trigger bindings.
- name: economy
description: Exact multi-currency accounts, atomic transfers and an immutable transaction ledger.
- name: claims
description: Persistent claims, membership and boundary protection.
- name: world
description: Persistent world-event lookup.
- name: rollback
description: Previewed, resumable and conflict-aware world rollback.
security:
- sessionCookie: []
paths:
/meta:
get:
summary: Read public API and first-owner setup state
operationId: getApiMetadata
tags: [system]
security: []
responses:
"200":
description: Public control-plane metadata
content:
application/json:
schema:
$ref: "#/components/schemas/ApiMetadata"
default: {$ref: "#/components/responses/Problem"}
/setup:
post:
summary: Create the first owner with a physical-console token
operationId: setupInitialOwner
tags: [auth]
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/SetupRequest"}
responses:
"201":
description: First owner created, token consumed, and session cookie issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/bootstrap:
post:
summary: Deprecated alias for /setup
operationId: bootstrapOwner
tags: [auth]
deprecated: true
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SetupRequest"
responses:
"201":
description: First owner created, token consumed, and session cookie issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/login:
post:
summary: Start an authenticated session
operationId: login
tags: [auth]
security: []
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username, password]
properties:
username: {type: string}
password: {type: string, maxLength: 1024}
totp: {type: [string, "null"], pattern: "^[0-9]{6}$"}
recoveryCode: {type: [string, "null"]}
responses:
"200":
description: Session cookie and CSRF token issued
headers:
Set-Cookie: {schema: {type: string}}
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
"429":
description: Login or account-wide second-factor attempt limit reached
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/session:
get:
summary: Read the current session or anonymous setup state
operationId: getCurrentSession
tags: [auth]
security: []
responses:
"200":
description: Current browser session state
content:
application/json:
schema: {$ref: "#/components/schemas/SessionInfo"}
default: {$ref: "#/components/responses/Problem"}
/auth/logout:
post:
summary: Revoke the current session
operationId: logout
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Session revoked}
default: {$ref: "#/components/responses/Problem"}
/auth/totp/enrollment:
post:
summary: Begin TOTP enrollment
operationId: beginTotpEnrollment
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [password]
properties:
password: {type: string, maxLength: 1024}
responses:
"200":
description: Unconfirmed TOTP secret and provisioning URI
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: object
required: [secret, provisioningUri, expiresAt]
properties:
secret: {type: string}
provisioningUri: {type: string, format: uri}
expiresAt: {type: string, format: date-time}
default: {$ref: "#/components/responses/Problem"}
/auth/totp/confirm:
post:
summary: Confirm TOTP and issue recovery codes
operationId: confirmTotpEnrollment
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [code]
properties:
code: {type: string, pattern: "^[0-9]{6}$"}
responses:
"200":
description: One-time recovery codes; retrying the same idempotency key repeats only this response
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: object
required: [recoveryCodes]
properties:
recoveryCodes: {type: array, minItems: 8, items: {type: string}}
"429":
description: Three unsuccessful second-factor attempts were made for this account within ten minutes
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/reauthenticate:
post:
summary: Refresh recent-authentication assurance with TOTP
operationId: reauthenticate
tags: [auth]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
password:
type: [string, "null"]
maxLength: 1024
description: Optional legacy reauthentication path; the Web UI uses TOTP only.
totp: {type: string, pattern: "^[0-9]{6}$"}
recoveryCode: {type: [string, "null"]}
responses:
"204":
description: The current server-side session now has recent-authentication assurance
"429":
description: Three unsuccessful second-factor attempts were made for this account within ten minutes
headers:
Retry-After: {schema: {type: integer, example: 600}}
content:
application/problem+json: {schema: {$ref: "#/components/schemas/Problem"}}
default: {$ref: "#/components/responses/Problem"}
/auth/sessions:
get:
summary: List account sessions
operationId: listSessions
tags: [auth]
responses:
"200":
description: Active sessions with redacted source information
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/json:
schema:
type: array
items: {$ref: "#/components/schemas/Session"}
default: {$ref: "#/components/responses/Problem"}
/auth/sessions/{sessionId}:
delete:
summary: Revoke an account session
operationId: revokeSession
tags: [auth]
parameters:
- name: sessionId
in: path
required: true
schema: {type: string, format: uuid}
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Session revoked or already absent}
default: {$ref: "#/components/responses/Problem"}
/accounts:
get:
summary: List Web management accounts
operationId: listAccounts
tags: [auth]
description: Owner-only. Password hashes, TOTP secrets and recovery codes are never returned.
responses:
"200":
description: Safety-filtered management accounts
content:
application/json:
schema:
type: array
maxItems: 100
items: {$ref: "#/components/schemas/Account"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a Web management account
operationId: createAccount
tags: [auth]
description: Owner-only; requires a TOTP-authenticated session and recent password authentication.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/AccountCreate"}
responses:
"201":
description: Account created
content:
application/json:
schema: {$ref: "#/components/schemas/Account"}
default: {$ref: "#/components/responses/Problem"}
/accounts/{accountId}:
patch:
summary: Change an account role or disabled state
operationId: updateAccount
tags: [auth]
description: Owner-only with TOTP and recent authentication. Demoting or disabling the last owner is rejected atomically and changing an account revokes its existing sessions.
parameters:
- $ref: "#/components/parameters/AccountId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/AccountPatch"}
responses:
"200":
description: Account updated
content:
application/json:
schema: {$ref: "#/components/schemas/Account"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a Web management account
operationId: deleteAccount
tags: [auth]
description: Owner-only with TOTP and recent authentication. Deleting the last owner is rejected atomically.
parameters:
- $ref: "#/components/parameters/AccountId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204": {description: Account and its sessions deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/healthz:
get:
summary: Read process health
operationId: getHealth
tags: [system]
security: []
servers:
- url: /
responses:
"200":
description: Process health (not authorization readiness)
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Health"
default:
$ref: "#/components/responses/Problem"
/events:
get:
summary: Stream management events
operationId: streamEvents
tags: [operations]
parameters:
- $ref: "#/components/parameters/LastEventId"
responses:
"200":
description: Server-sent events. Event types include status, operation, alert, policy and gap.
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
text/event-stream:
schema:
type: string
default:
$ref: "#/components/responses/Problem"
/status:
get:
summary: Read server status
operationId: getServerStatus
tags: [status]
responses:
"200":
description: Current server status snapshot
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ServerStatus"
default:
$ref: "#/components/responses/Problem"
/features:
get:
summary: Read effective feature availability
operationId: getFeatureFlags
tags: [system]
responses:
"200":
description: Configuration flags intersected with platform capabilities
content:
application/json:
schema: {$ref: "#/components/schemas/FeatureFlags"}
default: {$ref: "#/components/responses/Problem"}
/settings:
get:
summary: Read safety-filtered effective settings
operationId: getSettings
tags: [system]
responses:
"200":
description: Live settings plus any startup-only configuration waiting for restart
content:
application/json:
schema: {$ref: "#/components/schemas/ServerSettings"}
default: {$ref: "#/components/responses/Problem"}
put:
summary: Save editable server settings
operationId: updateSettings
tags: [system]
description: Owner-only. Requires CSRF, TOTP and recent authentication. Runtime-safe fields hot-apply; restartRequired is true only while startup-only fields differ. Legacy message properties are read-only after their one-time trigger migration.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/ServerSettings"}
responses:
"202":
description: Configuration persisted and runtime-safe fields applied
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default: {$ref: "#/components/responses/Problem"}
/triggers:
get:
summary: Read trigger groups and their trigger definitions
operationId: getTriggerWorkspace
tags: [triggers]
responses:
"200":
description: Complete trigger workspace
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a trigger
operationId: createTrigger
tags: [triggers]
description: Administrator or owner with recent TOTP authentication. Arbitrary command actions additionally require the owner-only console capability.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerInput"}
responses:
"202":
description: Trigger created and trigger index refreshed
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerMutationResult"}
default: {$ref: "#/components/responses/Problem"}
/triggers/catalog:
get:
summary: List supported events, conditions, actions, and searchable template variables
operationId: getTriggerCatalog
tags: [triggers]
responses:
"200":
description: Trigger authoring catalog
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerCatalog"}
default: {$ref: "#/components/responses/Problem"}
/triggers/validate:
post:
summary: Validate a visual trigger program or compile and validate XFE Script without saving
operationId: validateTriggerProgram
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
requestBody:
required: true
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/TriggerScriptValidationRequest"
- $ref: "#/components/schemas/TriggerVisualValidationRequest"
responses:
"200":
description: Compiled event-condition-action program
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerValidation"}
default: {$ref: "#/components/responses/Problem"}
/triggers/{triggerId}:
parameters:
- name: triggerId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a trigger with optimistic revision checking
operationId: updateTrigger
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/TriggerInput"
- type: object
required: [expectedRevision]
responses:
"202":
description: Trigger updated and trigger index refreshed
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerMutationResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a trigger
operationId: deleteTrigger
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Trigger deleted
content:
application/json:
schema: {$ref: "#/components/schemas/DeletionResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/trigger-groups:
post:
summary: Create a trigger group
operationId: createTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerGroupInput"}
responses:
"202":
description: Trigger group created
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
default: {$ref: "#/components/responses/Problem"}
/trigger-groups/{groupId}:
parameters:
- name: groupId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a trigger group with optimistic revision checking
operationId: updateTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/TriggerGroupInput"
- type: object
required: [expectedRevision]
responses:
"202":
description: Trigger group updated
content:
application/json:
schema: {$ref: "#/components/schemas/TriggerWorkspace"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete a trigger group and its triggers
operationId: deleteTriggerGroup
tags: [triggers]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Trigger group deleted with all contained triggers
content:
application/json:
schema: {$ref: "#/components/schemas/DeletionResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menus:
get:
summary: List interactive UI menu documents
operationId: listMenus
tags: [menus]
responses:
"200":
description: Menu workspace
content:
application/json:
schema: {$ref: "#/components/schemas/MenuWorkspace"}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create an interactive UI menu
operationId: createMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/MenuInput"}
responses:
"202":
description: Menu saved and immediately available to triggers
content:
application/json:
schema: {$ref: "#/components/schemas/MenuSaveResult"}
default: {$ref: "#/components/responses/Problem"}
/menus/catalog:
get:
summary: List menu positions, controls, events and compatible menu.control triggers
operationId: getMenuCatalog
tags: [menus]
responses:
"200":
description: Menu editor catalog
content:
application/json:
schema: {$ref: "#/components/schemas/MenuCatalog"}
default: {$ref: "#/components/responses/Problem"}
/menus/images:
get:
summary: Search uploaded images and vanilla/mod item, block and texture resources
operationId: searchMenuImages
tags: [menus]
parameters:
- name: query
in: query
schema: {type: string, maxLength: 128}
responses:
"200":
description: Bounded image search result
content:
application/json:
schema:
type: object
required: [items, query]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/MenuImage"}}
query: {type: string}
default: {$ref: "#/components/responses/Problem"}
/menus/images/preview:
get:
summary: Resolve an uploaded, vanilla, or installed-mod image reference for browser preview
operationId: getMenuImagePreview
tags: [menus]
parameters:
- name: reference
in: query
required: true
schema:
type: string
maxLength: 256
pattern: '^(uploaded|texture|item|block):'
responses:
"200":
description: Bounded PNG/JPEG preview represented as a data URL
content:
application/json:
schema:
type: object
required: [reference, mimeType, dataUrl]
properties:
reference: {type: string}
mimeType: {type: string, enum: [image/png, image/jpeg]}
dataUrl: {type: string}
"404": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menus/{menuId}:
parameters:
- name: menuId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a menu with optimistic revision checking
operationId: updateMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/MenuInput"
- type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Menu updated
content:
application/json:
schema: {$ref: "#/components/schemas/MenuSaveResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete an unreferenced menu
operationId: deleteMenu
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202": {description: Menu deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets:
post:
summary: Upload a bounded PNG or JPEG menu image
operationId: uploadMenuImage
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, dataUrl]
properties:
name: {type: string, minLength: 1, maxLength: 128}
dataUrl: {type: string, description: Base64 PNG/JPEG data URL; decoded content is limited to 256 KiB.}
responses:
"202":
description: Image stored
content:
application/json:
schema: {$ref: "#/components/schemas/MenuImage"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets/{assetId}:
parameters:
- name: assetId
in: path
required: true
schema: {type: string, format: uuid}
delete:
summary: Delete an image that is not referenced by a menu
operationId: deleteMenuImage
tags: [menus]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202": {description: Image deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/menu-assets/{assetId}/content:
get:
summary: Read one uploaded image as a data URL for the Web editor
operationId: getMenuImageContent
tags: [menus]
parameters:
- name: assetId
in: path
required: true
schema: {type: string, format: uuid}
responses:
"200":
description: Image data
content:
application/json:
schema:
type: object
required: [id, mimeType, dataUrl]
properties:
id: {type: string, format: uuid}
mimeType: {type: string, enum: [image/png, image/jpeg]}
dataUrl: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy:
get:
summary: Read the economy workspace and aggregate overview
operationId: getEconomyWorkspace
tags: [economy]
responses:
"200":
description: Currencies and aggregate metrics
content:
application/json:
schema: {$ref: "#/components/schemas/EconomyWorkspace"}
default: {$ref: "#/components/responses/Problem"}
/economy/currencies:
get:
summary: List every configured currency
operationId: listCurrencies
tags: [economy]
responses:
"200":
description: Currency definitions, primary first
content:
application/json:
schema: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/Currency"}}
default: {$ref: "#/components/responses/Problem"}
post:
summary: Create a currency
operationId: createCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/CurrencyInput"}
responses:
"202": {description: Currency created and immediately available to accounts and triggers}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/currencies/{currencyId}:
parameters:
- name: currencyId
in: path
required: true
schema: {type: string, format: uuid}
put:
summary: Replace a currency with optimistic revision checking
operationId: updateCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CurrencyInput"
- type: object
required: [expectedRevision]
properties:
expectedRevision: {type: integer, minimum: 0}
responses:
"202": {description: Currency updated}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
delete:
summary: Delete an unused non-primary currency
operationId: deleteCurrency
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedRevision, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 512}
responses:
"202": {description: Unused currency deleted}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/accounts:
get:
summary: Search player economy accounts
operationId: listEconomyAccounts
tags: [economy]
parameters:
- {name: query, in: query, schema: {type: string, maxLength: 128}}
- {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}
responses:
"200":
description: Economy accounts and all currency balances
content:
application/json:
schema:
type: object
required: [items]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/EconomyAccount"}}
nextCursor: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy/transactions:
get:
summary: Search the immutable economy ledger
operationId: listEconomyTransactions
tags: [economy]
parameters:
- {name: query, in: query, schema: {type: string, maxLength: 128}}
- {name: player, in: query, schema: {type: string}}
- {name: currency, in: query, schema: {type: string}}
- {name: kind, in: query, schema: {type: string, enum: [initial, deposit, withdraw, set, transfer]}}
- {name: before, in: query, schema: {type: string, format: date-time}}
- {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}
responses:
"200":
description: Ledger entries ordered newest first
content:
application/json:
schema:
type: object
required: [items]
properties:
items: {type: array, maxItems: 200, items: {$ref: "#/components/schemas/EconomyTransaction"}}
nextCursor: {type: string}
default: {$ref: "#/components/responses/Problem"}
/economy/adjustments:
post:
summary: Deposit, withdraw or set one player's exact balance
operationId: adjustEconomyBalance
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [playerId, playerName, currency, operation, amount, reason]
properties:
playerId: {type: string, format: uuid}
playerName: {type: string, minLength: 1, maxLength: 64}
currency: {type: string, description: Currency UUID or code.}
operation: {type: string, enum: [deposit, withdraw, set]}
amount: {$ref: "#/components/schemas/EconomyAmount"}
reason: {type: string, minLength: 1, maxLength: 512}
expectedRevision: {type: integer, minimum: 0}
responses:
"202":
description: Balance changed atomically and ledger entry committed
content: {application/json: {schema: {$ref: "#/components/schemas/EconomyChange"}}}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/economy/transfers:
post:
summary: Atomically transfer currency between two players
operationId: transferEconomyBalance
tags: [economy]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sourcePlayerId, sourcePlayerName, targetPlayerId, targetPlayerName, currency, amount, reason]
properties:
sourcePlayerId: {type: string, format: uuid}
sourcePlayerName: {type: string, minLength: 1, maxLength: 64}
targetPlayerId: {type: string, format: uuid}
targetPlayerName: {type: string, minLength: 1, maxLength: 64}
currency: {type: string, description: Currency UUID or code.}
amount: {$ref: "#/components/schemas/EconomyAmount"}
reason: {type: string, minLength: 1, maxLength: 512}
expectedSourceRevision: {type: integer, minimum: 0}
responses:
"202":
description: Both balances and one ledger entry committed in one transaction
content: {application/json: {schema: {$ref: "#/components/schemas/EconomyChange"}}}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/metrics:
get:
summary: Export OpenMetrics
operationId: getMetrics
tags: [status]
servers:
- url: /
security:
- metricsBearer: []
responses:
"200":
description: Token-protected OpenMetrics exposition
headers:
X-Request-ID: {$ref: "#/components/headers/RequestId"}
content:
application/openmetrics-text:
schema: {type: string}
default: {$ref: "#/components/responses/Problem"}
/players:
get:
summary: List players
operationId: listPlayers
tags: [players]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: online
in: query
schema:
type: boolean
- name: query
in: query
description: Case-insensitive player name or UUID search text.
schema:
type: string
maxLength: 128
responses:
"200":
description: Player page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerPage"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}:
get:
summary: Read player details
operationId: getPlayer
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Player details
headers:
ETag:
description: Player snapshot revision
schema: {type: string}
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerDetail"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/actions:
post:
summary: Preview or execute an online-player action
operationId: executePlayerAction
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerActionRequest"
responses:
"202":
description: Returns PREVIEW_REQUIRED with a frozen target/token, or an accepted/completed operation
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/inventory:
get:
summary: Read an online player's inventory
operationId: getPlayerInventory
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Online player inventory and ender chest revisions
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/InventorySnapshot"
default:
$ref: "#/components/responses/Problem"
patch:
summary: Compare-and-swap inventory slots
operationId: updatePlayerInventory
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/InventoryPatch"
responses:
"202":
description: Audited compare-and-swap result and slot diff
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/InventoryUpdateResult"
"409":
$ref: "#/components/responses/Problem"
default:
$ref: "#/components/responses/Problem"
/players/{playerId}/ender-chest:
get:
summary: Read an online player's ender chest
operationId: getPlayerEnderChest
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
responses:
"200":
description: Ender-chest slots and compare-and-swap revision
content:
application/json:
schema: {$ref: "#/components/schemas/InventorySnapshot"}
default: {$ref: "#/components/responses/Problem"}
patch:
summary: Compare-and-swap ender-chest slots
operationId: updatePlayerEnderChest
tags: [players]
parameters:
- $ref: "#/components/parameters/PlayerId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/InventoryPatch"}
responses:
"202":
description: Audited compare-and-swap result and slot diff
content:
application/json:
schema: {$ref: "#/components/schemas/InventoryUpdateResult"}
"409": {$ref: "#/components/responses/Problem"}
default: {$ref: "#/components/responses/Problem"}
/policies:
get:
summary: List policy versions
operationId: listPolicies
tags: [policies]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Immutable policy versions
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyPage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Create a policy draft
operationId: createPolicyDraft
tags: [policies]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyDraft"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}:
get:
summary: Read a policy version
operationId: getPolicyVersion
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
responses:
"200":
description: Policy version with validation and diff
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyVersion"
default:
$ref: "#/components/responses/Problem"
delete:
summary: Discard the current unpublished draft
operationId: discardPolicyDraft
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyMutationRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/validate:
post:
summary: Validate a policy draft
operationId: validatePolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200":
description: Validation result; this does not publish the policy
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyValidation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/diff:
get:
summary: Diff a policy version against another revision
operationId: diffPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- name: from
in: query
schema: {type: integer, format: int64, minimum: 0}
responses:
"200":
description: Rule-level immutable version diff
content:
application/json:
schema: {type: object, additionalProperties: true}
default:
$ref: "#/components/responses/Problem"
/policies/simulate:
post:
summary: Simulate policy decisions
operationId: simulatePolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicySimulationRequest"
responses:
"200":
description: Explained active-policy decision without executing the command
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyDecision"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/publish:
post:
summary: Publish a validated policy
operationId: publishPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyPublishRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/policies/{versionId}/rollback:
post:
summary: Restore a historical policy
operationId: rollbackPolicy
tags: [policies]
parameters:
- $ref: "#/components/parameters/VersionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PolicyMutationRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/audit:
get:
summary: Search audit events
operationId: listAuditEvents
tags: [audit]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: actor
in: query
schema: {type: string}
- name: action
in: query
schema: {type: string}
- name: query
in: query
deprecated: true
description: Compatibility alias for the action filter.
schema: {type: string}
- name: target
in: query
schema: {type: string}
- name: requestId
in: query
schema: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
- name: from
in: query
schema: {type: string, format: date-time}
- name: to
in: query
schema: {type: string, format: date-time}
responses:
"200":
description: Redacted audit page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/AuditPage"
default:
$ref: "#/components/responses/Problem"
/operations:
post:
summary: Submit a structured player or system operation
operationId: submitOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema: {$ref: "#/components/schemas/OperationRequest"}
responses:
"202":
description: Preview requirement, running job, or completed operation
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default: {$ref: "#/components/responses/Problem"}
/operations/{operationId}:
get:
summary: Read operation status
operationId: getOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/OperationId"
responses:
"200":
description: Operation state and result summary
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Operation"
default:
$ref: "#/components/responses/Problem"
/operations/{operationId}/cancel:
post:
summary: Cancel an operation
operationId: cancelOperation
tags: [operations]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Operation tracking or pending preview cancelled
content:
application/json:
schema: {$ref: "#/components/schemas/Operation"}
default:
$ref: "#/components/responses/Problem"
/console/commands:
post:
summary: Execute an owner console command
operationId: executeConsoleCommand
tags: [console]
description: Owner-only and disabled by default. The session must have TOTP assurance and recent password reauthentication.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [command, reason]
properties:
command: {type: string, minLength: 1, maxLength: 4096}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/moderation/cases:
get:
summary: List moderation cases
operationId: listModerationCases
tags: [moderation]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: playerId
in: query
schema: {type: string, format: uuid}
- name: active
in: query
schema: {type: boolean}
responses:
"200":
description: Moderation case page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ModerationCasePage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Open a moderation case
operationId: createModerationCase
tags: [moderation]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateModerationCase"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/moderation/cases/{caseId}/actions/{actionId}/revoke:
post:
summary: Revoke one sanction action in a moderation case
operationId: revokeModerationAction
tags: [moderation]
parameters:
- $ref: "#/components/parameters/CaseId"
- $ref: "#/components/parameters/ActionId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Reason"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance:
get:
summary: Read maintenance state
operationId: getMaintenance
tags: [maintenance]
responses:
"200":
description: Maintenance mode and upcoming plans
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceState"
default:
$ref: "#/components/responses/Problem"
put:
summary: Change maintenance state
operationId: setMaintenance
tags: [maintenance]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceRequest"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance/schedules:
post:
summary: Schedule a structured action
operationId: createMaintenanceSchedule
tags: [maintenance]
description: Schedules only structured actions, never arbitrary console commands. Graceful stops announce their target on creation, every five minutes in the final hour, and every second in the final minute.
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledAction"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/maintenance/announcements:
post:
summary: Broadcast an audited announcement immediately
operationId: announceMaintenanceMessage
tags: [maintenance]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [message, reason]
properties:
message: {type: string, minLength: 1}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Announcement broadcast}
default: {$ref: "#/components/responses/Problem"}
/claims:
get:
summary: List claims
operationId: listClaims
tags: [claims]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: dimension
in: query
schema: {type: string}
- name: ownerId
in: query
schema: {type: string, format: uuid}
responses:
"200":
description: Claim page
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/ClaimPage"
default:
$ref: "#/components/responses/Problem"
post:
summary: Create a claim
operationId: createClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateClaim"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/claims/{claimId}:
patch:
summary: Update a claim
operationId: updateClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/merge-patch+json:
schema:
$ref: "#/components/schemas/ClaimPatch"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
delete:
summary: Delete a claim using an optimistic revision check
operationId: deleteClaim
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [revision, reason]
properties:
revision: {type: integer, format: int64, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Deleted claim snapshot}
default: {$ref: "#/components/responses/Problem"}
/claims/{claimId}/transfer:
post:
summary: Begin an owner-to-owner claim transfer
operationId: beginClaimTransfer
tags: [claims]
parameters:
- $ref: "#/components/parameters/ClaimId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [actorId, newOwnerId, reason]
properties:
actorId: {type: string, format: uuid}
newOwnerId: {type: string, format: uuid}
validity: {type: string, default: 10m}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Short-lived single-use transfer ticket}
default: {$ref: "#/components/responses/Problem"}
/claims/transfers/{transferToken}/confirm:
post:
summary: Confirm a claim transfer as its intended recipient
operationId: confirmClaimTransfer
tags: [claims]
parameters:
- name: transferToken
in: path
required: true
schema: {type: string, format: uuid}
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [acceptingPlayerId, reason]
properties:
acceptingPlayerId: {type: string, format: uuid}
reason: {type: string, minLength: 1, maxLength: 500}
responses:
"200": {description: Updated claim with its new owner}
default: {$ref: "#/components/responses/Problem"}
/world/changes:
get:
summary: Search world changes
operationId: lookupWorldChanges
tags: [world]
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: actorId
in: query
schema: {type: string, format: uuid}
- name: dimension
in: query
schema: {type: string}
- name: x
in: query
schema: {type: integer}
- name: y
in: query
schema: {type: integer}
- name: z
in: query
schema: {type: integer}
- name: radius
in: query
schema: {type: integer, minimum: 0, maximum: 2048}
- name: claimId
in: query
schema: {type: string, format: uuid}
- name: action
in: query
schema: {type: string}
- name: resourceId
in: query
schema: {type: string}
- name: from
in: query
schema: {type: string, format: date-time}
- name: to
in: query
schema: {type: string, format: date-time}
responses:
"200":
description: World event page; gaps are returned explicitly
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/WorldChangePage"
default:
$ref: "#/components/responses/Problem"
/rollbacks/preview:
post:
summary: Preview a rollback
operationId: previewRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RollbackSelection"
responses:
"200":
description: Dry-run fixed to a watermark; does not modify the world
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/RollbackPreview"
default:
$ref: "#/components/responses/Problem"
/rollbacks:
post:
summary: Execute a rollback preview
operationId: executeRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [previewId, confirmationToken, reason]
properties:
previewId: {type: string, format: uuid}
confirmationToken: {type: string}
reason: {type: string, minLength: 1, maxLength: 500}
forceConflicts: {type: boolean, default: false}
loadChunks: {type: boolean, default: false}
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/pause:
post:
summary: Pause a rollback
operationId: pauseRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/resume:
post:
summary: Resume a rollback
operationId: resumeRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
$ref: "#/components/responses/AcceptedOperation"
default:
$ref: "#/components/responses/Problem"
/rollbacks/{operationId}/cancel:
post:
summary: Cancel an active rollback after reconciling any in-flight item
operationId: cancelRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200": {description: Cancelled rollback checkpoint}
default: {$ref: "#/components/responses/Problem"}
/rollbacks/{operationId}/redo/preview:
post:
summary: Preview redo of a completed rollback
operationId: previewRedoRollback
tags: [rollback]
parameters:
- $ref: "#/components/parameters/OperationId"
- $ref: "#/components/parameters/CsrfToken"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200": {description: Fixed-watermark redo preview}
default:
$ref: "#/components/responses/Problem"
components:
securitySchemes:
sessionCookie:
type: apiKey
in: cookie
name: XFESM_SESSION
metricsBearer:
type: http
scheme: bearer
headers:
RequestId:
description: Correlation ID generated by the server or accepted from a validated request header
schema: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
parameters:
Cursor:
name: cursor
in: query
description: Opaque cursor from the previous page; clients must not parse it.
schema: {type: string}
Limit:
name: limit
in: query
schema: {type: integer, minimum: 1, maximum: 200, default: 50}
LastEventId:
name: Last-Event-ID
in: header
schema: {type: string}
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
description: Unique key for this logical mutation; reuse it when retrying an uncertain response.
schema: {type: string, minLength: 8, maxLength: 128, pattern: "^[A-Za-z0-9._:-]+$"}
CsrfToken:
name: X-CSRF-Token
in: header
required: true
description: Session-bound double-submit token required for same-origin mutations.
schema: {type: string, minLength: 16, maxLength: 256}
PlayerId:
name: playerId
in: path
required: true
schema: {type: string, format: uuid}
AccountId:
name: accountId
in: path
required: true
schema: {type: string, format: uuid}
VersionId:
name: versionId
in: path
required: true
schema: {type: string, pattern: '^policy-[0-9]+$'}
OperationId:
name: operationId
in: path
required: true
schema: {type: string, format: uuid}
CaseId:
name: caseId
in: path
required: true
schema: {type: string, format: uuid}
ActionId:
name: actionId
in: path
required: true
schema: {type: string, format: uuid}
ClaimId:
name: claimId
in: path
required: true
schema: {type: string, format: uuid}
responses:
Problem:
description: RFC 9457 problem details
headers:
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
AcceptedOperation:
description: Preview requirement, accepted job, or operation completed within the bounded dispatch window
headers:
Location:
description: Relative operation status URL
schema: {type: string}
X-Request-ID:
$ref: "#/components/headers/RequestId"
content:
application/json:
schema:
$ref: "#/components/schemas/Operation"
schemas:
ApiMetadata:
type: object
required: [name, apiVersion, setupRequired, serverReady]
properties:
name: {type: string}
apiVersion: {type: string, const: v1}
setupRequired: {type: boolean}
serverReady: {type: boolean}
SetupRequest:
type: object
required: [bootstrapToken, username, password]
properties:
bootstrapToken: {type: string, minLength: 16, maxLength: 256}
username: {$ref: "#/components/schemas/AccountUsername"}
password: {type: string, minLength: 12, maxLength: 1024}
Actor:
type: object
required: [id, displayName, roles, permissions, totpEnabled, totpVerified, reauthenticationRequired]
properties:
id: {type: string, format: uuid}
displayName: {type: string}
roles:
type: array
minItems: 1
items: {type: string, enum: [observer, helper, moderator, administrator, owner]}
permissions: {type: array, items: {type: string}}
totpEnabled: {type: boolean}
totpVerified: {type: boolean}
reauthenticationRequired: {type: boolean}
SessionInfo:
type: object
required: [authenticated, bootstrapRequired]
properties:
authenticated: {type: boolean}
actor: {$ref: "#/components/schemas/Actor"}
csrfToken: {type: string}
bootstrapRequired: {type: boolean}
expiresAt: {type: string, format: date-time}
Session:
type: object
required: [id, createdAt, lastSeenAt, expiresAt, current]
properties:
id: {type: string, format: uuid}
createdAt: {type: string, format: date-time}
lastSeenAt: {type: string, format: date-time}
expiresAt: {type: string, format: date-time}
current: {type: boolean}
source: {type: string, description: Redacted source label}
AccountUsername:
type: string
minLength: 3
maxLength: 32
pattern: "^[A-Za-z0-9_.-]+$"
AccountRole:
type: string
enum: [observer, helper, moderator, administrator, owner]
Account:
type: object
required: [id, username, role, totpEnabled, disabled, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
username: {$ref: "#/components/schemas/AccountUsername"}
role: {$ref: "#/components/schemas/AccountRole"}
totpEnabled: {type: boolean}
disabled: {type: boolean}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
lastLoginAt: {type: [string, "null"], format: date-time}
AccountCreate:
type: object
additionalProperties: false
required: [username, password, role]
properties:
username: {$ref: "#/components/schemas/AccountUsername"}
password: {type: string, minLength: 12, maxLength: 1024, writeOnly: true}
role: {$ref: "#/components/schemas/AccountRole"}
AccountPatch:
type: object
additionalProperties: false
minProperties: 1
properties:
role: {$ref: "#/components/schemas/AccountRole"}
disabled: {type: boolean}
Problem:
type: object
required: [type, title, status, detail, requestId]
properties:
type: {type: string, format: uri-reference}
title: {type: string}
status: {type: integer, minimum: 400, maximum: 599}
detail: {type: string}
instance: {type: [string, "null"], format: uri-reference}
requestId: {type: string, pattern: "^[A-Za-z0-9._-]{8,64}$"}
extensions: {type: object, additionalProperties: true}
PageMetadata:
type: object
required: [hasMore]
properties:
nextCursor: {type: [string, "null"]}
hasMore: {type: boolean}
Health:
type: object
required: [http, serverReady, sseClients]
properties:
http: {type: string, enum: [running, starting, stopping, stopped, failed]}
serverReady: {type: boolean}
sseClients: {type: integer, minimum: 0}
ServerStatus:
type: object
required: [sampledAt, uptimeSeconds, playersOnline]
properties:
sampledAt: {type: string, format: date-time}
serverName: {type: string}
minecraftVersion: {type: string}
forgeVersion: {type: string}
onlineMode: {type: boolean}
uptimeSeconds: {type: integer, minimum: 0}
tps: {type: number, minimum: 0, maximum: 20}
mspt:
type: object
properties:
average: {type: number, minimum: 0}
p95: {type: number, minimum: 0}
p99: {type: number, minimum: 0}
jitter: {type: number, minimum: 0}
cpuLoad: {type: number, minimum: 0, maximum: 1}
heapUsedBytes: {type: integer, minimum: 0}
heapMaxBytes: {type: integer, minimum: 0}
gcPauseMs: {type: integer, minimum: 0}
diskFreeBytes: {type: integer, minimum: 0}
playersOnline: {type: integer, minimum: 0}
playersMax: {type: integer, minimum: 0}
averagePingMs: {type: number, minimum: 0}
dimensions:
type: array
items:
type: object
properties:
id: {type: string}
loadedChunks: {type: integer, minimum: 0}
entities: {type: integer, minimum: 0}
samples:
type: array
items:
type: object
required: [at]
properties:
at: {type: string, format: date-time}
tps: {type: number, minimum: 0, maximum: 20}
mspt: {type: number, minimum: 0}
FeatureFlags:
type: object
required: [consoleEnabled, moderationEnabled, claimsEnabled, worldTrackingEnabled, rollbackEnabled, joinExperienceEnabled, metricsEnabled]
properties:
consoleEnabled: {type: boolean}
moderationEnabled: {type: boolean}
claimsEnabled: {type: boolean}
worldTrackingEnabled: {type: boolean}
rollbackEnabled: {type: boolean}
joinExperienceEnabled: {type: boolean, description: Legacy compatibility status; authoring moved to triggers.}
metricsEnabled: {type: boolean}
ServerSettings:
type: object
required: [bindAddress, port, trustedProxyCidrs, crashProtection, features, metricsRequireToken, offlineMode, sparkDetected, blueMapDetected]
properties:
bindAddress: {type: string}
port: {type: integer, minimum: 1, maximum: 65535}
trustedProxyCidrs: {type: array, items: {type: string}}
publicBaseUrl: {type: string, format: uri}
idleSessionSeconds: {type: integer, minimum: 1}
absoluteSessionSeconds: {type: integer, minimum: 1}
recentAuthenticationSeconds: {type: integer, minimum: 1}
httpThreads: {type: integer, minimum: 2, maximum: 64}
maximumSseClients: {type: integer, minimum: 1, maximum: 1000}
webConsoleEnabled: {type: boolean}
rawItemEditingEnabled: {type: boolean}
metricsEnabled: {type: boolean}
moderationEnabled: {type: boolean}
claimsEnabled: {type: boolean}
worldTrackingEnabled: {type: boolean}
rollbackEnabled: {type: boolean}
joinExperienceEnabled: {type: boolean, readOnly: true, deprecated: true}
joinWelcomeEnabled: {type: boolean, readOnly: true, deprecated: true}
joinWelcomeMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
firstJoinMessageEnabled: {type: boolean, readOnly: true, deprecated: true}
firstJoinMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
dailyAnnouncementsEnabled: {type: boolean, readOnly: true, deprecated: true}
dailyAnnouncements:
type: array
maxItems: 20
items: {type: string, maxLength: 65536}
readOnly: true
deprecated: true
announcementTimeZone: {type: string, examples: [Asia/Shanghai]}
defaultMessageSender:
type: string
minLength: 1
maxLength: 64
default: XFEServerManager
description: Sender prefix inherited by plain messages and rich messages that do not define an explicit sender. Applied immediately without a restart.
rulesReminderEnabled: {type: boolean, readOnly: true, deprecated: true}
rulesMessage: {type: string, maxLength: 65536, readOnly: true, deprecated: true}
maintenanceJoinReminderEnabled: {type: boolean, readOnly: true, deprecated: true}
crashProtection: {$ref: "#/components/schemas/CrashProtectionSettings"}
restartRequired: {type: boolean}
features: {$ref: "#/components/schemas/FeatureFlags"}
serverLocale: {type: string}
metricsRequireToken: {type: boolean, const: true}
offlineMode: {type: boolean}
sparkDetected: {type: boolean}
blueMapDetected: {type: boolean}
CrashProtectionSettings:
type: object
additionalProperties: false
description: Runtime-safe preemptive limits for entity floods, command-block loops, slow ticks, loaded chunks, and memory pressure. Players and existing living entities are never removed.
required: [enabled, scanIntervalTicks, itemEntitiesPerDimension, itemEntitiesPerChunk, livingEntitiesPerDimension, livingEntitiesPerChunk, totalEntitiesPerDimension, totalEntitiesPerChunk, entitiesPerNamespacePerDimension, loadedChunksPerDimension, spawnBurstLimit, spawnBurstWindowTicks, commandBlockCommandsPerSecond, slowTickMillis, consecutiveSlowTicks, heapUsagePercent, blockExcessSpawns, removeExcessItems, stopRunawayCommandBlocks]
properties:
enabled: {type: boolean, default: true}
scanIntervalTicks: {type: integer, minimum: 20, maximum: 1200, default: 100}
itemEntitiesPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 2000}
itemEntitiesPerChunk: {type: integer, minimum: 1, maximum: 1000000, default: 256}
livingEntitiesPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 2000}
livingEntitiesPerChunk: {type: integer, minimum: 1, maximum: 1000000, default: 128}
totalEntitiesPerDimension: {type: integer, minimum: 1, maximum: 2000000, default: 5000}
totalEntitiesPerChunk: {type: integer, minimum: 1, maximum: 2000000, default: 512}
entitiesPerNamespacePerDimension: {type: integer, minimum: 1, maximum: 2000000, default: 512}
loadedChunksPerDimension: {type: integer, minimum: 1, maximum: 1000000, default: 8000}
spawnBurstLimit: {type: integer, minimum: 1, maximum: 1000000, default: 400}
spawnBurstWindowTicks: {type: integer, minimum: 20, maximum: 72000, default: 100}
commandBlockCommandsPerSecond: {type: integer, minimum: 1, maximum: 100000, default: 100}
slowTickMillis: {type: integer, minimum: 50, maximum: 60000, default: 200}
consecutiveSlowTicks: {type: integer, minimum: 1, maximum: 1200, default: 3}
heapUsagePercent: {type: integer, minimum: 50, maximum: 99, default: 90}
blockExcessSpawns: {type: boolean, default: true}
removeExcessItems: {type: boolean, default: true}
stopRunawayCommandBlocks: {type: boolean, default: true}
PlayerSummary:
type: object
required: [uuid, name, online]
properties:
uuid: {type: string, format: uuid}
name: {type: string}
online: {type: boolean}
pingMs: {type: integer, minimum: 0}
roles: {type: array, items: {type: string}}
opLevel: {type: integer, minimum: 0, maximum: 4}
gameMode: {type: string}
health: {type: number, minimum: 0}
foodLevel: {type: integer, minimum: 0}
location:
allOf:
- $ref: "#/components/schemas/Position"
- type: object
required: [dimension]
properties:
dimension: {type: string}
PlayerDetail:
allOf:
- $ref: "#/components/schemas/PlayerSummary"
- type: object
properties:
connectedAt: {type: string, format: date-time}
PlayerPage:
type: object
required: [items]
properties:
items: {type: array, items: {$ref: "#/components/schemas/PlayerSummary"}}
nextCursor: {type: string}
Position:
type: object
required: [x, y, z]
properties:
x: {type: number}
y: {type: number}
z: {type: number}
Reason:
type: object
required: [reason]
properties:
reason: {type: string, minLength: 1, maxLength: 500}
PlayerActionRequest:
type: object
required: [action, reason]
properties:
action:
type: string
enum: [message, kick, teleport, recall, heal, feed, gamemode, clear_effects, whitelist, ban]
reason: {type: string, minLength: 1, maxLength: 500}
value: {type: string}
confirmedTargetUuid:
type: string
format: uuid
deprecated: true
description: Optional UI cross-check; the path and frozen preview UUID are authoritative.
previewToken: {type: string, format: uuid}
ItemStack:
type: object
required: [slot, itemId, count, structuredData, opaqueDataPresent, opaqueDataFingerprint]
properties:
slot: {type: integer, minimum: 0}
itemId: {type: string}
count: {type: integer, minimum: 0}
structuredData: {type: object, additionalProperties: {type: string}}
opaqueDataPresent:
type: boolean
readOnly: true
description: True when server-side NBT/data components exist but are deliberately redacted.
opaqueDataFingerprint:
type: string
readOnly: true
pattern: "^([0-9a-f]{64})?$"
description: Non-reversible change marker; never a restorable raw payload.
ItemStackPatch:
type: object
additionalProperties: false
required: [slot, itemId, count, structuredData]
properties:
slot: {type: integer, minimum: 0}
itemId: {type: string}
count: {type: integer, minimum: 0, maximum: 127}
structuredData: {type: object, additionalProperties: {type: string}}
InventorySnapshot:
type: object
required: [playerUuid, container, revision, online, slots]
properties:
playerUuid: {type: string, format: uuid}
container: {type: string, enum: [inventory, ender_chest]}
revision: {type: integer, minimum: 0}
online: {type: boolean}
slots: {type: array, items: {$ref: "#/components/schemas/ItemStack"}}
InventoryPatch:
type: object
required: [expectedRevision, updates, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
updates:
type: array
minItems: 1
items:
$ref: "#/components/schemas/ItemStackPatch"
reason: {type: string, minLength: 1, maxLength: 500}
rawEditingRequested: {type: boolean, default: false}
InventorySlotDiff:
type: object
required: [slot, before, after]
properties:
slot: {type: integer, minimum: 0}
before: {$ref: "#/components/schemas/ItemStack"}
after: {$ref: "#/components/schemas/ItemStack"}
InventoryUpdateResult:
allOf:
- $ref: "#/components/schemas/Operation"
- type: object
required: [revision, diffs]
properties:
revision: {type: integer, format: int64, minimum: 0}
diffs:
type: array
items: {$ref: "#/components/schemas/InventorySlotDiff"}
PolicyDraft:
type: object
required: [expectedActiveVersion, description, rules]
properties:
expectedActiveVersion: {type: integer, format: int64, minimum: 0}
description: {type: string, minLength: 1, maxLength: 1000}
rules: {type: array, items: {type: object, additionalProperties: true}}
PolicyPublishRequest:
type: object
required: [version, reason]
properties:
version: {type: integer, format: int64, minimum: 1}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyMutationRequest:
type: object
required: [expectedActiveVersion, reason]
properties:
expectedActiveVersion: {type: integer, format: int64, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyVersion:
type: object
required: [id, version, name, state, groupCount, ruleCount, updatedAt]
properties:
id: {type: string, pattern: '^policy-[0-9]+$'}
version: {type: integer, format: int64, minimum: 0}
name: {type: string}
description: {type: string}
state: {type: string, enum: [DRAFT, ACTIVE, ARCHIVED]}
groupCount: {type: integer, minimum: 0}
ruleCount: {type: integer, minimum: 0}
updatedAt: {type: string, format: date-time}
updatedBy: {type: string}
checksum: {type: string}
rules:
type: array
items:
allOf:
- $ref: "#/components/schemas/PolicyRule"
validation: {$ref: "#/components/schemas/PolicyValidation"}
PolicyRule:
type: object
required: [id, enabled, groupId, groupName, groupEnabled, tier, subject, command, effect, constraints, reason]
properties:
id: {type: string, pattern: '^[A-Za-z0-9._-]+$'}
enabled: {type: boolean}
groupId: {type: string, pattern: '^[A-Za-z0-9._-]{1,64}$'}
groupName: {type: string, minLength: 1, maxLength: 128}
groupEnabled: {type: boolean}
tier: {type: string, enum: [DEFAULT, OP_LEVEL, ROLE, UUID, HARD_SAFETY]}
subject: {type: object, additionalProperties: true}
command: {type: object, additionalProperties: true}
effect: {type: string, enum: [PASS_THROUGH, DENY, GRANT, CONSTRAIN]}
constraints: {type: object, additionalProperties: true}
reason: {type: string, minLength: 1, maxLength: 1000}
PolicyPage:
type: object
required: [items, nextCursor]
properties:
items: {type: array, items: {$ref: "#/components/schemas/PolicyVersion"}}
nextCursor: {type: [string, "null"]}
PolicyValidation:
type: object
required: [valid, errors, warnings]
properties:
valid: {type: boolean}
errors:
type: array
items: {$ref: "#/components/schemas/PolicyValidationIssue"}
warnings:
type: array
items: {$ref: "#/components/schemas/PolicyValidationIssue"}
PolicyValidationIssue:
type: object
required: [ruleId, code, message]
properties:
ruleId: {type: string}
code: {type: string}
message: {type: string}
PolicySimulationRequest:
type: object
required: [command]
properties:
command: {type: string, minLength: 1, maxLength: 4096}
playerUuid: {type: [string, "null"], format: uuid}
PolicyDecision:
type: object
required: [decision, explanation, matchedRuleIds, normalizedCommand]
properties:
decision: {type: string, enum: [PASS_THROUGH, DENY, GRANT, CONSTRAIN]}
explanation: {type: array, items: {type: string}}
matchedRuleIds: {type: array, items: {type: string}}
normalizedCommand: {type: string}
AuditEvent:
type: object
required: [id, at, actor, source, action, result]
properties:
id: {type: string, format: uuid}
at: {type: string, format: date-time}
actor: {type: string}
source: {type: string}
target: {type: [string, "null"]}
action: {type: string}
reason: {type: [string, "null"]}
requestId: {type: string}
result: {type: string}
durationMs: {type: integer, minimum: 0}
AuditPage:
type: object
required: [items, nextCursor]
properties:
items: {type: array, items: {$ref: "#/components/schemas/AuditEvent"}}
nextCursor: {type: [string, "null"]}
OperationRequest:
type: object
required: [action, reason]
properties:
action: {type: string}
target: {}
reason: {type: string, minLength: 1, maxLength: 512}
parameters: {type: object, additionalProperties: true}
previewToken: {type: string, format: uuid}
Operation:
type: object
required: [id, kind, state]
properties:
id: {type: string, format: uuid}
kind: {type: string}
state: {type: string, enum: [PREVIEW_REQUIRED, QUEUED, RUNNING, PAUSED, SUCCEEDED, PARTIAL, FAILED, CANCELLED]}
createdAt: {type: string, format: date-time}
completedAt: {type: string, format: date-time}
expiresAt: {type: string, format: date-time}
progress: {type: number, minimum: 0, maximum: 1}
message: {type: string}
requestId: {type: string}
previewToken: {type: string, format: uuid}
targets:
type: array
items:
type: object
required: [uuid]
properties:
uuid: {type: string, format: uuid}
name: {type: string}
result:
oneOf:
- {type: object, additionalProperties: true}
- {type: integer}
results: {type: array, items: {type: object, additionalProperties: true}}
revision: {type: integer, minimum: 0}
diffs: {type: array, items: {type: object, additionalProperties: true}}
error: {$ref: "#/components/schemas/Problem"}
CreateModerationCase:
type: object
required: [playerId, action, reason]
properties:
playerId: {type: string, format: uuid}
action: {type: string, enum: [warn, mute, kick, tempban, ban]}
reason: {type: string, minLength: 1, maxLength: 500}
message: {type: string, minLength: 1, maxLength: 500, description: Player-facing message; defaults to reason when omitted.}
duration: {type: string, description: "Required for tempban. Examples include 30m, 2h, 7d, or an ISO-8601 duration."}
templateId: {type: [string, "null"]}
expiresAt: {type: [string, "null"], format: date-time}
evidenceUrls: {type: array, items: {type: string, format: uri}}
staffNote: {type: string, maxLength: 4000}
ModerationCase:
type: object
required: [id, playerId, action, reason, createdAt, active]
properties:
id: {type: string, format: uuid}
playerId: {type: string, format: uuid}
action: {type: string}
reason: {type: string}
message: {type: string}
createdAt: {type: string, format: date-time}
expiresAt: {type: [string, "null"], format: date-time}
active: {type: boolean}
remainingSeconds: {type: integer, description: "Seconds remaining, or -1 for a permanent/no-expiry action."}
evidenceUrls: {type: array, items: {type: string, format: uri}}
ModerationCasePage:
type: object
required: [items, page]
properties:
items: {type: array, items: {$ref: "#/components/schemas/ModerationCase"}}
page: {$ref: "#/components/schemas/PageMetadata"}
MaintenanceState:
type: object
required: [enabled, whitelistOnly, schedules, defaultMessageSender]
properties:
enabled: {type: boolean}
whitelistOnly: {type: boolean}
message: {type: string}
defaultMessageSender: {type: string, minLength: 1, maxLength: 64}
endsAt: {type: [string, "null"], format: date-time}
schedules: {type: array, items: {$ref: "#/components/schemas/ScheduledAction"}}
MaintenanceRequest:
type: object
required: [enabled, reason]
properties:
enabled: {type: boolean}
whitelistOnly: {type: boolean, default: true}
message: {type: string, maxLength: 500}
endsAt: {type: [string, "null"], format: date-time}
countdownSeconds: {type: integer, minimum: 0, maximum: 86400}
reason: {type: string, minLength: 1, maxLength: 500}
ScheduledAction:
type: object
required: [kind, executeAt, reason]
properties:
id: {type: string, format: uuid, readOnly: true}
kind: {type: string, enum: [announce, enable_maintenance, disable_maintenance, save_flush, graceful_stop]}
executeAt: {type: string, format: date-time}
arguments: {type: object, additionalProperties: true}
reason: {type: string, minLength: 1, maxLength: 500}
status: {type: string, enum: [PENDING, CLAIMED, COMPLETED, CANCELLED], readOnly: true}
attempts: {type: integer, minimum: 0, readOnly: true}
leaseUntil: {type: [string, "null"], format: date-time, readOnly: true}
completedAt: {type: [string, "null"], format: date-time, readOnly: true}
lastError: {type: string, readOnly: true}
createdBy: {type: string, readOnly: true}
TriggerWorkspace:
type: object
required: [groups, totalTriggers]
properties:
groups:
type: array
maxItems: 256
items: {$ref: "#/components/schemas/TriggerGroup"}
totalTriggers: {type: integer, minimum: 0, maximum: 1024}
TriggerCatalog:
type: object
required: [events, operators, actions, actionParameters, variables, variableSyntax, defaultMessageSender]
properties:
events: {type: array, items: {type: string}}
operators: {type: array, items: {type: string}}
actions: {type: array, items: {type: string}}
actionParameters:
type: object
additionalProperties:
type: array
items: {type: string}
variables:
type: array
minItems: 100
items: {$ref: "#/components/schemas/TriggerVariableDefinition"}
variableSyntax:
$ref: "#/components/schemas/TriggerVariableSyntax"
defaultMessageSender: {type: string, minLength: 1, maxLength: 64}
TriggerVariableDefinition:
type: object
required: [key, nameZh, nameEn, descriptionZh, descriptionEn, category, scopes,
example, sampleValue, formatHint, type, events, templateAllowed, conditionAllowed]
properties:
key:
type: string
description: Variable expression without the surrounding braces
nameZh: {type: string}
nameEn: {type: string}
descriptionZh: {type: string}
descriptionEn: {type: string}
category: {type: string}
scopes:
type: array
minItems: 1
items: {type: string}
description: Semantic UI scopes such as global, player-event, world, command, or schedule
example:
type: string
description: Complete placeholder ready for insertion
sampleValue:
type: string
description: Example resolved value, or an empty string when no fixed sample is useful
formatHint: {type: string}
type: {type: string, enum: [string, number, boolean, instant, datetime]}
events:
type: array
minItems: 1
items: {type: string}
description: Exact event IDs or bounded glob patterns; `*` means every event
templateAllowed: {type: boolean}
conditionAllowed: {type: boolean}
TriggerVariableSyntax:
type: object
required: [delimiter, formattedTime, formatHint]
properties:
delimiter: {type: string, example: "{variable}"}
formattedTime: {type: string, example: "{server.time:uuuu-MM-dd HH:mm:ss}"}
formatHint: {type: string}
TriggerMutationResult:
type: object
required: [trigger, workspace]
properties:
trigger: {$ref: "#/components/schemas/Trigger"}
workspace: {$ref: "#/components/schemas/TriggerWorkspace"}
TriggerValidation:
type: object
required: [valid, event, conditionMode, conditions, actions]
properties:
valid: {type: boolean, const: true}
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
TriggerScriptValidationRequest:
type: object
additionalProperties: false
required: [script]
properties:
script: {type: string, minLength: 1, maxLength: 65536}
TriggerVisualValidationRequest:
type: object
additionalProperties: false
required: [event, conditionMode, conditions, actions]
properties:
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
DeletionResult:
type: object
required: [deleted, id]
properties:
deleted: {type: boolean, const: true}
id: {type: string, format: uuid}
TriggerGroup:
allOf:
- $ref: "#/components/schemas/TriggerGroupInput"
- type: object
required: [id, revision, triggers, createdBy, createdAt, updatedAt, migrated]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
triggers: {type: array, maxItems: 256, items: {$ref: "#/components/schemas/Trigger"}}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
migrated: {type: boolean}
TriggerGroupInput:
type: object
required: [name, enabled]
properties:
name: {type: string, minLength: 1, maxLength: 120}
description: {type: string, maxLength: 500}
enabled: {type: boolean}
expectedRevision: {type: integer, minimum: 0}
Trigger:
allOf:
- $ref: "#/components/schemas/TriggerInput"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt, migrated]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
migrated: {type: boolean}
TriggerInput:
type: object
required: [groupId, name, enabled, mode]
properties:
groupId: {type: string, format: uuid}
name: {type: string, minLength: 1, maxLength: 120}
description: {type: string, maxLength: 500}
enabled: {type: boolean}
mode: {type: string, enum: [visual, code]}
event: {$ref: "#/components/schemas/TriggerEvent"}
conditionMode: {type: string, enum: [all, any]}
conditions:
type: array
items: {$ref: "#/components/schemas/TriggerCondition"}
actions:
type: array
minItems: 1
description: Root action nodes. Action and condition trees may be nested without an artificial authoring limit.
items: {$ref: "#/components/schemas/TriggerAction"}
script: {type: string, maxLength: 65536}
expectedRevision: {type: integer, minimum: 0}
oneOf:
- title: Visual trigger
required: [event, conditionMode, conditions, actions]
properties:
mode: {const: visual}
- title: XFE Script trigger
required: [script]
properties:
mode: {const: code}
TriggerEvent:
type: object
required: [type, configuration]
properties:
type: {type: string, minLength: 1, maxLength: 80}
configuration:
type: object
maxProperties: 16
description: schedule.daily uses time and timezone. schedule.interval accepts legacy total seconds or hours/minutes/seconds components, normalizes them to total seconds (1..31536000), and aligns execution to server-local wall-clock boundaries. player.command_trigger uses command plus an optional legacy whitespace-separated arguments declaration. protection.* events use threshold and cooldownSeconds; count-based item/mob/entity events also accept scope=dimension|chunk, mod_entity_overflow accepts namespace, and slow_tick accepts consecutive.
additionalProperties: {type: string, maxLength: 4096}
arguments:
type: array
description: Recursive Brigadier alternatives for player.command_trigger. Siblings are alternatives and children form the next input level.
items: {$ref: "#/components/schemas/TriggerCommandArgument"}
variables:
type: array
description: Strongly typed trigger-local or server-global state declarations. Missing visibility/storage fields migrate as trigger-local trigger storage.
items: {$ref: "#/components/schemas/TriggerStateVariable"}
TriggerCommandArgument:
type: object
required: [name, type, literal, optional, errorMessage, minimum, maximum, suggestions, children]
properties:
name: {type: string, pattern: '^[a-z][a-z0-9_-]{0,31}$'}
type: {type: string, description: A supported vanilla Brigadier argument family or literal.}
literal: {type: string, maxLength: 128}
optional: {type: boolean}
errorMessage: {type: string, maxLength: 256}
minimum: {type: string}
maximum: {type: string}
suggestions: {type: array, maxItems: 64, items: {type: string, minLength: 1, maxLength: 128}}
children: {type: array, items: {$ref: "#/components/schemas/TriggerCommandArgument"}}
TriggerStateVariable:
type: object
required: [name, type, initialValue]
properties:
name: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_-]{0,47}$'}
type:
type: string
description: Scalar type, legacy list, or recursively nested array<T>/dictionary<K,V>; dictionary keys must be scalar.
initialValue:
type: string
maxLength: 65536
description: Scalars use their text form; arrays and dictionaries use strictly typed JSON.
visibility: {type: string, enum: [trigger, global], default: trigger}
storage:
type: string
enum: [server, player, dimension, trigger]
description: Selects one shared value, a value per triggering player, per dimension, or per executing trigger.
TriggerCondition:
type: object
required: [field, operator, value]
properties:
field: {type: string, minLength: 1, maxLength: 120}
operator: {type: string, enum: [eq, neq, contains, not_contains, starts_with, not_starts_with, ends_with, not_ends_with, matches, not_matches, gt, gte, lt, lte, between, not_between, in, not_in, empty, not_empty, 'true', 'false', exists, not_exists]}
value: {type: string, maxLength: 4096}
TriggerAction:
type: object
required: [type, parameters]
description: An executable action, or a structural condition whose children run only when its field/operator/value passes. Only condition nodes may have children; authoring does not impose an artificial node-count or nesting-depth limit.
properties:
type: {type: string, enum: [condition, send_player, broadcast, title, actionbar, sound, server_command, player_command, kick, teleport, give_item, clear_inventory, set_gamemode, add_effect, remove_effects, heal, feed, set_time, set_weather, whitelist_add, whitelist_remove, ban, pardon, log, variable, wait, run_trigger, open_menu, close_menu, economy_deposit, economy_withdraw, economy_set_balance, economy_transfer, economy_deposit_player, economy_withdraw_player, economy_set_player_balance, economy_transfer_players]}
parameters:
type: object
maxProperties: 16
description: Condition nodes use field, operator, and value. Command actions accept showFeedback=true|false and default to false. Rich message envelopes are limited to 256 segments and 8192 visible characters and are validated on save.
additionalProperties: {type: string, maxLength: 65536}
children:
type: array
description: Non-empty for condition nodes; omitted or empty for executable actions.
items: {$ref: "#/components/schemas/TriggerAction"}
MenuWorkspace:
type: object
required: [menus, totalMenus]
properties:
menus: {type: array, maxItems: 512, items: {$ref: "#/components/schemas/Menu"}}
totalMenus: {type: integer, minimum: 0, maximum: 512}
MenuSaveResult:
type: object
required: [menu, workspace]
properties:
menu: {$ref: "#/components/schemas/Menu"}
workspace: {$ref: "#/components/schemas/MenuWorkspace"}
Menu:
allOf:
- $ref: "#/components/schemas/MenuInput"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
MenuInput:
type: object
required: [name, width, height, popupPosition, backgroundColor, controls]
properties:
name: {type: string, minLength: 1, maxLength: 96}
description: {type: string, maxLength: 1024}
width: {type: integer, minimum: 120, maximum: 1920}
height: {type: integer, minimum: 80, maximum: 1080}
popupPosition: {type: string, enum: [center, top, bottom, left, right, top_left, top_right, bottom_left, bottom_right, custom]}
offsetX: {type: integer, minimum: -8192, maximum: 8192}
offsetY: {type: integer, minimum: -8192, maximum: 8192}
pauseGame: {type: boolean, default: false}
backgroundColor: {type: string, pattern: '^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$'}
controls: {type: array, maxItems: 128, items: {$ref: "#/components/schemas/MenuControl"}}
MenuControl:
type: object
required: [id, type, x, y, width, height, zIndex, visibleWhen, properties, events]
properties:
id: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_.-]{0,63}$'}
type: {type: string, enum: [text, rich_text, button, icon_button, image, panel, border, progress, input, checkbox, slider, item_slot, separator, spacer]}
x: {type: integer, minimum: 0}
y: {type: integer, minimum: 0}
width: {type: integer, minimum: 1, maximum: 1920}
height: {type: integer, minimum: 1, maximum: 1080}
zIndex: {type: integer, minimum: -1000, maximum: 1000}
visibleWhen: {type: string, maxLength: 512}
properties:
type: object
maxProperties: 48
additionalProperties: {type: string, maxLength: 16384}
events: {type: array, maxItems: 8, items: {$ref: "#/components/schemas/MenuControlEvent"}}
MenuControlEvent:
type: object
required: [event, triggerId, submenuId, closeMenu]
properties:
event: {type: string, enum: [click, double_click, change, submit, toggle, hover, focus, blur]}
triggerId: {type: string, description: "Empty, or UUID of a menu.control trigger."}
submenuId: {type: string, description: "Empty, or UUID of an existing acyclic submenu."}
closeMenu: {type: boolean}
MenuCatalog:
type: object
required: [controlTypes, popupPositions, controlEvents, triggers]
properties:
controlTypes: {type: array, items: {type: string}}
popupPositions: {type: array, items: {type: string}}
controlEvents: {type: array, items: {type: string}}
triggers:
type: array
items:
type: object
required: [id, name, enabled]
properties:
id: {type: string, format: uuid}
name: {type: string}
enabled: {type: boolean}
MenuImage:
type: object
required: [reference, name, type, source]
properties:
id: {type: string, format: uuid}
reference: {type: string, description: 'uploaded:, texture:, item:, or block: reference.'}
name: {type: string}
type: {type: string, enum: [uploaded, texture, item, block]}
source: {type: string}
mimeType: {type: string, enum: [image/png, image/jpeg]}
width: {type: integer, minimum: 1, maximum: 1024}
height: {type: integer, minimum: 1, maximum: 1024}
sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
dataUrl: {type: string}
EconomyAmount:
type: string
pattern: '^-?(0|[1-9][0-9]*)(\.[0-9]+)?$'
description: Exact base-10 amount. Floating-point JSON numbers are intentionally not accepted.
CurrencyFields:
type: object
required: [code, name, symbol, icon, fractionDigits, initialBalance, minimumBalance, maximumBalance, playerTransferAllowed, enabled, primary]
properties:
code: {type: string, pattern: '^[a-z][a-z0-9_]{0,31}$'}
name: {type: string, minLength: 1, maxLength: 64}
symbol: {type: string, minLength: 1, maxLength: 16}
icon: {type: string, description: 'uploaded:, texture:, item:, or block: reference.'}
fractionDigits: {type: integer, minimum: 0, maximum: 6}
initialBalance: {$ref: "#/components/schemas/EconomyAmount"}
minimumBalance: {$ref: "#/components/schemas/EconomyAmount"}
maximumBalance: {$ref: "#/components/schemas/EconomyAmount"}
playerTransferAllowed: {type: boolean, description: Allows player-initiated command payments; audited management and trigger transfers remain available.}
enabled: {type: boolean}
primary: {type: boolean}
CurrencyInput:
allOf:
- $ref: "#/components/schemas/CurrencyFields"
- type: object
required: [reason]
properties:
reason: {type: string, minLength: 1, maxLength: 512}
Currency:
allOf:
- $ref: "#/components/schemas/CurrencyFields"
- type: object
required: [id, revision, createdBy, createdAt, updatedAt]
properties:
id: {type: string, format: uuid}
revision: {type: integer, minimum: 0}
createdBy: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
EconomyBalance:
type: object
required: [currencyId, currencyCode, currencyName, symbol, icon, fractionDigits, amount, revision, currencyEnabled, updatedAt]
properties:
currencyId: {type: string, format: uuid}
currencyCode: {type: string}
currencyName: {type: string}
symbol: {type: string}
icon: {type: string}
fractionDigits: {type: integer, minimum: 0, maximum: 6}
amount: {$ref: "#/components/schemas/EconomyAmount"}
revision: {type: integer, minimum: 0}
currencyEnabled: {type: boolean}
updatedAt: {type: string, format: date-time}
EconomyAccount:
type: object
required: [playerId, playerName, balances, updatedAt]
properties:
playerId: {type: string, format: uuid}
playerName: {type: string}
balances: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/EconomyBalance"}}
updatedAt: {type: string, format: date-time}
EconomyTransaction:
type: object
required: [id, currencyId, currencyCode, kind, sourcePlayerName, targetPlayerName, amount, sourceBalanceBefore, sourceBalanceAfter, targetBalanceBefore, targetBalanceAfter, reason, actor, origin, correlationId, createdAt]
properties:
id: {type: string, format: uuid}
currencyId: {type: string, format: uuid}
currencyCode: {type: string}
kind: {type: string, enum: [initial, deposit, withdraw, set, transfer]}
sourcePlayerId: {type: string, format: uuid}
sourcePlayerName: {type: string}
targetPlayerId: {type: string, format: uuid}
targetPlayerName: {type: string}
amount: {$ref: "#/components/schemas/EconomyAmount"}
sourceBalanceBefore: {type: string}
sourceBalanceAfter: {type: string}
targetBalanceBefore: {type: string}
targetBalanceAfter: {type: string}
reason: {type: string}
actor: {type: string}
origin: {type: string, enum: [system, web, command, trigger]}
correlationId: {type: string}
createdAt: {type: string, format: date-time}
EconomyCurrencySummary:
type: object
required: [currencyId, code, name, symbol, icon, fractionDigits, enabled, primary, accountCount, totalSupply, minimumBalance, maximumBalance, transactionCount, transferVolume24h]
properties:
currencyId: {type: string, format: uuid}
code: {type: string}
name: {type: string}
symbol: {type: string}
icon: {type: string}
fractionDigits: {type: integer}
enabled: {type: boolean}
primary: {type: boolean}
accountCount: {type: integer, minimum: 0}
totalSupply: {$ref: "#/components/schemas/EconomyAmount"}
minimumBalance: {$ref: "#/components/schemas/EconomyAmount"}
maximumBalance: {$ref: "#/components/schemas/EconomyAmount"}
transactionCount: {type: integer, minimum: 0}
transferVolume24h: {$ref: "#/components/schemas/EconomyAmount"}
EconomyWorkspace:
type: object
required: [currencies, overview]
properties:
currencies: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/Currency"}}
overview:
type: object
required: [currencies, observedAt]
properties:
currencies: {type: array, maxItems: 64, items: {$ref: "#/components/schemas/EconomyCurrencySummary"}}
observedAt: {type: string, format: date-time}
EconomyChange:
type: object
required: [currency, transaction]
properties:
currency: {$ref: "#/components/schemas/Currency"}
transaction: {$ref: "#/components/schemas/EconomyTransaction"}
sourceBalance: {$ref: "#/components/schemas/EconomyBalance"}
targetBalance: {$ref: "#/components/schemas/EconomyBalance"}
ChunkPosition:
type: object
required: [x, z]
properties:
x: {type: integer}
z: {type: integer}
Claim:
type: object
required: [id, dimension, ownerId, chunks, members, flags, revision]
properties:
id: {type: string, format: uuid}
name: {type: string}
dimension: {type: string}
ownerId: {type: string, format: uuid}
chunks: {type: array, items: {$ref: "#/components/schemas/ChunkPosition"}}
members:
type: object
additionalProperties: {type: string, enum: [manager, member, trusted]}
flags:
type: object
additionalProperties: {type: boolean}
revision: {type: integer, minimum: 0}
CreateClaim:
type: object
required: [name, dimension, chunks]
properties:
name: {type: string, minLength: 1, maxLength: 64}
dimension: {type: string}
chunks: {type: array, minItems: 1, items: {$ref: "#/components/schemas/ChunkPosition"}}
adminOverride: {type: boolean, default: false}
ClaimPatch:
type: object
required: [expectedRevision, reason]
properties:
expectedRevision: {type: integer, minimum: 0}
name: {type: string, minLength: 1, maxLength: 64}
chunks: {type: array, minItems: 1, items: {$ref: "#/components/schemas/ChunkPosition"}}
members: {type: object, additionalProperties: {type: string}}
flags: {type: object, additionalProperties: {type: boolean}}
transferTo: {type: string, format: uuid}
transferConfirmation: {type: string}
reason: {type: string, minLength: 1, maxLength: 500}
ClaimPage:
type: object
required: [items, page]
properties:
items: {type: array, items: {$ref: "#/components/schemas/Claim"}}
page: {$ref: "#/components/schemas/PageMetadata"}
WorldChange:
type: object
required: [id, timestamp, tick, dimension, position, action, resourceId, restorable]
properties:
id: {type: string, format: uuid}
timestamp: {type: string, format: date-time}
tick: {type: integer}
dimension: {type: string}
position: {$ref: "#/components/schemas/Position"}
actorId: {type: [string, "null"], format: uuid}
cause: {type: string}
action: {type: string}
resourceId: {type: string}
modFingerprint: {type: [string, "null"]}
restorable: {type: boolean}
incompatibility: {type: [string, "null"]}
transactionId: {type: string, format: uuid}
WorldChangePage:
type: object
required: [items, page, gaps]
properties:
items: {type: array, items: {$ref: "#/components/schemas/WorldChange"}}
page: {$ref: "#/components/schemas/PageMetadata"}
gaps:
type: array
items:
type: object
properties:
from: {type: string, format: date-time}
to: {type: string, format: date-time}
reason: {type: string}
RollbackSelection:
type: object
required: [from, to, reason]
properties:
from: {type: string, format: date-time}
to: {type: string, format: date-time}
actorId: {type: [string, "null"], format: uuid}
dimension: {type: [string, "null"]}
center: {$ref: "#/components/schemas/Position"}
radius: {type: integer, minimum: 0, maximum: 2048}
claimId: {type: [string, "null"], format: uuid}
actions: {type: array, items: {type: string}}
includeEntitiesAndItems: {type: boolean, default: false}
reason: {type: string, minLength: 1, maxLength: 500}
RollbackPreview:
type: object
required: [id, watermark, expiresAt, selected, applicable, conflicts, unloadedChunks, gaps, incompatible, confirmationToken]
properties:
id: {type: string, format: uuid}
watermark: {type: integer, format: int64, minimum: 0}
expiresAt: {type: string, format: date-time}
selected: {type: integer, minimum: 0}
applicable: {type: integer, minimum: 0}
conflicts: {type: integer, minimum: 0}
unloadedChunks: {type: integer, minimum: 0}
gaps: {type: integer, minimum: 0}
incompatible: {type: integer, minimum: 0}
estimatedChunkLoads: {type: integer, minimum: 0, maximum: 128}
confirmationToken: {type: string}