Files
sencho/docs/openapi.yaml
T
Anso a1804c8fbe docs: comprehensive review and refresh of all documentation (#374)
* docs: comprehensive review and refresh of all documentation pages

Reviewed every doc page against the current app state after the v0.38
dashboard redesign. Updated content, fixed inaccuracies, and refreshed
all screenshots at 1920x1080.

Pages updated:
- introduction: expanded feature list to 25 items across 6 subsections
- quickstart: fixed docker run command (Docker Hub, auto JWT, COMPOSE_DIR)
- configuration: replaced personal paths with generic /home/user/docker
- sso-quickstart: fixed Settings navigation reference
- sso: added SSO_LDAP_DISPLAY_NAME env var
- overview: added 8 missing feature sections (labels, API tokens, schedules, etc.)
- dashboard: complete rewrite for new health bar, gauges, stack health table
- stack-management: updated for UP/DN indicators, rollback button, split actions
- editor: rewritten for two-column layout, inline stats, embedded terminal
- resources: updated Quick Clean docs, added network topology and inspect
- app-store: updated categories, deploy sheet details, permission gate, settings
- openapi.yaml: fixed YAML parsing error on line 1831

Screenshots refreshed: 14 images across 6 feature areas.

* docs: review and update observability, console, multi-node, and compatibility pages

- Global Observability: fix log format fields, add download button docs,
  split display limits into memory buffer vs rendered rows, correct
  settings labels
- Host Console: remove internal implementation details per security
  docs policy, add stack directory behavior, expand header bar docs,
  remove unverified scrollback claim
- Multi-Node: add Compose Directory field, document connection test
  details panel, fix edit/delete node behavior, simplify token security
  section, remove internal details
- Node Compatibility: add missing self-update capability, remove
  internal endpoint paths and cache TTL, move from Features to
  Reference group in navigation
- Refresh all screenshots for the redesigned UI (7 images)

* docs: review and refresh fleet, remote updates, labels, alerts, routing, and webhooks pages

- Fleet View: added node updates modal, container detail, version/update/critical badges, Tags filter
- Remote Updates: removed internal details, added capability cross-link, fast polling
- Stack Labels: three creation methods, two assignment methods, 10 colors, bulk actions screenshot
- Alerts & Notifications: fixed metric labels, added notification popover detail, status banner
- Notification Routing: HTTPS requirement, rule card layout, channel terminology fix
- Webhooks: corrected license tier to Admiral, matched action labels to UI, removed internal security details, added local-only note
- Troubleshooting: centralized entries from remote-updates, stack-labels, notification-routing
- Refreshed all screenshots at 1920x1080, removed 11 orphaned images

* docs: review and refresh RBAC, user management, and atomic deployments pages

- RBAC: added missing Auditor role (5th role), updated permission matrix, fixed license tier references, documented username/password validation rules, self-deletion protection
- Atomic Deployments: added "Which operations are protected" section covering webhooks/schedules/app store, removed internal backup path, fixed license tier to Skipper/Admiral
- Screenshots: cropped to dialog element per updated strategic cropping guideline, removed 2 orphaned images

* docs: review and refresh fleet-wide backups and audit log pages

Update fleet-backups page to reflect current inline create form, add
scheduled snapshots section, document the detail view and restore dialog,
expand RBAC table to all five roles. Update audit log page to document
expanded row detail fields, pagination, refresh button, and data retention
screenshot. Replace all screenshots with fresh captures at 1920x720.

* docs: review and refresh API tokens and private registries pages

- API Tokens: clarify Full Admin scope, add Managing tokens section
  with card details, document revocation confirmation dialog, add
  usage tracking to security model, refresh screenshot
- Private Registries: add Managing registries section with card details
  and action buttons, document edit behavior, fix URL auto-fill
  description, remove encryption algorithm name per security policy,
  fix grammar, refresh both screenshots

* docs: review and refresh auto-update policies, scheduled operations, and SSO pages

- Auto-Update Policies: document all 8 table columns, expand action buttons,
  add "All Stacks" wildcard option, fix field labels, add CSV export and
  pagination details, refresh screenshots
- Scheduled Operations: fix System Prune target description, add Task List
  table columns, restructure create dialog fields with action-specific
  annotations, rewrite execution history with column table, refresh screenshots
- SSO: remove encryption algorithm name per security policy, add LDAP and
  OIDC configuration field tables, document provider card controls (Save,
  Test Connection, Remove, Active badge), refresh screenshots
- Move SSO troubleshooting entries to centralized troubleshooting page

* docs: review and refresh licensing & billing page

Update upgrade card feature lists to match actual tier gating (Skipper:
fleet view, webhooks, labels, atomic deployments, backups, auto-update
policies; Admiral: scoped RBAC, SSO, audit log, host console, API
tokens, private registries, scheduled operations). Add flex layout to
align upgrade card buttons at the bottom. Replace stale screenshot with
fresh community and active license captures. Add feature breakdown
subsection and profile menu billing shortcut to docs.

* docs: review and refresh settings reference and security advisories pages

Settings Reference: add 5 missing sections (SSO, API Tokens, Registries,
Labels, Routing), expand Users from 2 to 5 roles, fix System Limits and
Developer field labels to match UI, restructure Developer into Streaming
and Data Retention sub-tables, update App Store and Support sections,
refresh overview screenshot.

Security Advisories: restructure into versioned sections (v0.25.x
hardening and v0.19-v0.24 CVE remediation), expand from 3 bullet points
to 10 specific improvements, fix GitHub URL from SaelixCode to AnsoCode,
redact internal details per security docs policy.

Remove "Sencho Pro" product name from all three pages, replaced with
tier names (Community, Skipper, Admiral).

* docs: review and refresh troubleshooting page, remove architecture and development guides

- Rewrote forgotten password section to remove exposed SQL and table names
- Updated all Settings navigation paths to Profile > Settings > X
- Fixed network topology from "tab" to "view mode", added Pro license note
- Updated Prune Networks to current "Prune Dead Networks" label
- Corrected update check cooldown from vague to 2 minutes
- Consolidated two network creation error sections into one
- Removed hardcoded version reference (v0.34.0)
- Replaced em dashes throughout
- Deleted architecture.mdx (exposes internal implementation details)
- Deleted development.mdx (contributor guide belongs in repo, not public docs)
- Removed both pages from docs.json navigation

* docs: review and refresh operations pages (backup, upgrade, self-hosting, troubleshooting)

Backup & Restore:
- Added missing encryption.key to all backup/restore procedures
- Added Warning about restoring db without matching encryption key
- Added cross-reference to Fleet-Wide Backups for paid tiers
- Removed false claim about no built-in backup scheduler
- Updated cron example to include encryption key copy

Upgrading Sencho:
- Removed internal migration details (table names, column specs, encryption algorithm)
- Replaced with high-level migration summary per security docs policy
- Added encryption.key to pre-upgrade backup command
- Updated version pinning example from 0.25.3 to 0.38.0
- Added Remote Updates cross-reference for Skipper/Admiral users

Self-Hosting Best Practices:
- Removed JWT_SECRET from env var table (auto-generated, not an env var)
- Removed PORT from env var table (hardcoded to 3000, not configurable)
- Added API_RATE_LIMIT to env var table (actually exists in code)
- Fixed listen port description from "configurable" to "fixed"
- Updated resource recommendations based on measured footprint audit
- Removed su-exec reference (internal implementation detail)
- Upgraded data directory Note to Warning with file names

Troubleshooting:
- Fixed "Pro features" heading to "Paid features" with correct tier names
2026-04-04 21:32:51 -04:00

2783 lines
88 KiB
YAML

openapi: 3.1.0
info:
title: Sencho API
version: 0.25.3
description: |
REST API for Sencho, a self-hosted Docker Compose management dashboard.
Sencho exposes a public API for automating stack deployments, managing webhooks,
monitoring fleet health, and integrating with CI/CD pipelines.
## Authentication
All authenticated endpoints accept a Bearer token in the `Authorization` header.
Generate API tokens from **Settings > API Tokens** in the Sencho dashboard (requires Admiral license).
```
Authorization: Bearer YOUR_API_TOKEN
```
## Node Routing
Sencho manages multiple nodes (local and remote). To target a specific node,
include the `x-node-id` header or `?nodeId=` query parameter. If omitted,
the request targets the default node.
## License Tiers
Some endpoints require a Pro or Admiral license. Requests to gated endpoints
on Community Edition return `403` with `code: "PRO_REQUIRED"` or `code: "ADMIRAL_REQUIRED"`.
contact:
name: Sencho
url: https://sencho.io
license:
name: BSL 1.1
url: https://github.com/AnsoCode/Sencho/blob/main/LICENSE
servers:
- url: "{protocol}://{host}:{port}"
description: Your Sencho instance
variables:
protocol:
default: https
enum: [http, https]
host:
default: localhost
port:
default: "3000"
security:
- bearerAuth: []
tags:
- name: Health
description: Instance health check
- name: Stacks
description: Create, read, update, delete, and operate Docker Compose stacks
- name: Containers
description: List and manage running containers
- name: API Tokens
description: Manage scoped API tokens (Admiral license required)
- name: Webhooks
description: Configure and trigger deployment webhooks (Pro license required)
- name: Nodes
description: Manage local and remote Sencho nodes
- name: Fleet
description: Multi-node fleet overview and snapshots (Pro license required)
- name: Scheduled Tasks
description: Configure recurring automated operations (Admiral license required)
- name: Registries
description: Manage private container registry credentials (Admiral license required). These endpoints are only accessible via browser sessions — API tokens receive `SCOPE_DENIED`.
- name: Image Updates
description: Check for available container image updates across stacks
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: API token generated from Settings > API Tokens. Scopes — `read-only`, `deploy-only`, or `full-admin`.
webhookSignature:
type: apiKey
in: header
name: X-Webhook-Signature
description: HMAC-SHA256 signature for webhook trigger requests. Compute as `sha256=HMAC(request_body, webhook_secret)`.
parameters:
stackName:
name: stackName
in: path
required: true
description: >
Stack directory name. Must match `^[a-zA-Z0-9_-]+$` (alphanumeric characters,
hyphens, and underscores only). Returns `400 Invalid stack name` if the name
contains path separators, dots, spaces, or other special characters.
schema:
type: string
pattern: '^[a-zA-Z0-9_-]+$'
example: my-stack
nodeId:
name: x-node-id
in: header
required: false
description: Target a specific node by ID. If omitted, the default node is used. Can also be passed as `?nodeId=` query parameter.
schema:
type: integer
example: 1
nodeIdQuery:
name: nodeId
in: query
required: false
description: Target a specific node by ID (alternative to `x-node-id` header).
schema:
type: integer
example: 1
idPath:
name: id
in: path
required: true
description: Numeric resource ID.
schema:
type: integer
schemas:
Error:
type: object
required: [error]
properties:
error:
type: string
description: Human-readable error message.
code:
type: string
description: Machine-readable error code (e.g., `PRO_REQUIRED`, `SCOPE_DENIED`).
enum: [PRO_REQUIRED, ADMIRAL_REQUIRED, SCOPE_DENIED]
SuccessMessage:
type: object
required: [message]
properties:
message:
type: string
SuccessBoolean:
type: object
required: [success]
properties:
success:
type: boolean
example: true
Container:
type: object
properties:
Id:
type: string
description: Docker container ID.
Names:
type: array
items:
type: string
description: Container names (prefixed with `/`).
Service:
type: string
description: Compose service name (if part of a stack).
State:
type: string
description: Container state.
enum: [running, exited, paused, restarting, dead, created]
Status:
type: string
description: Human-readable status string (e.g., "Up 2 hours").
Ports:
type: array
items:
type: object
properties:
PrivatePort:
type: integer
PublicPort:
type: integer
Node:
type: object
required: [id, name, type, compose_dir, is_default, created_at]
properties:
id:
type: integer
name:
type: string
type:
type: string
enum: [local, remote]
compose_dir:
type: string
description: Base directory for Docker Compose stacks on this node.
is_default:
type: integer
enum: [0, 1]
description: Whether this is the default node (1 = true).
api_url:
type: string
description: Remote node API URL (only for remote nodes).
api_token:
type: string
description: Redacted API token for remote node authentication.
created_at:
type: integer
description: Unix timestamp (seconds).
Webhook:
type: object
required: [id, name, stack_name, action, secret, enabled, created_at]
properties:
id:
type: integer
name:
type: string
stack_name:
type: string
action:
type: string
enum: [deploy, restart, stop, start, pull]
secret:
type: string
description: Masked secret (e.g., `****...****`). Full secret is only returned on creation.
enabled:
type: integer
enum: [0, 1]
created_at:
type: integer
description: Unix timestamp (seconds).
WebhookExecution:
type: object
properties:
id:
type: integer
webhook_id:
type: integer
triggered_at:
type: integer
description: Unix timestamp (seconds).
status:
type: string
response:
type: string
error:
type: ["string", "null"]
ApiToken:
type: object
required: [id, name, scope, user_id, created_at]
properties:
id:
type: integer
name:
type: string
scope:
type: string
enum: [read-only, deploy-only, full-admin]
user_id:
type: integer
created_at:
type: integer
description: Unix timestamp (seconds).
expires_at:
type: ["integer", "null"]
description: Unix timestamp (seconds) or null for no expiry.
revoked_at:
type: ["integer", "null"]
last_used_at:
type: ["integer", "null"]
FleetNodeOverview:
type: object
properties:
id:
type: integer
name:
type: string
type:
type: string
enum: [local, remote]
status:
type: string
enum: [online, offline]
stats:
type: ["object", "null"]
description: Container statistics for the node.
systemStats:
type: ["object", "null"]
description: Host system resource statistics.
stacks:
type: ["integer", "null"]
description: Number of stacks on this node.
FleetSnapshot:
type: object
required: [id, description, created_by, created_at, node_count, stack_count]
properties:
id:
type: integer
description:
type: string
created_by:
type: string
created_at:
type: integer
description: Unix timestamp (seconds).
node_count:
type: integer
stack_count:
type: integer
skipped_nodes:
type: string
description: JSON-stringified array of skipped node names.
FleetSnapshotDetail:
allOf:
- $ref: "#/components/schemas/FleetSnapshot"
- type: object
properties:
nodes:
type: array
items:
type: object
properties:
nodeId:
type: integer
nodeName:
type: string
stacks:
type: array
items:
type: object
properties:
stackName:
type: string
files:
type: array
items:
type: object
properties:
filename:
type: string
content:
type: string
ScheduledTask:
type: object
required: [id, name, target_type, action, cron_expression, enabled, created_by, created_at, updated_at]
properties:
id:
type: integer
name:
type: string
target_type:
type: string
enum: [stack, fleet, system]
target_id:
type: ["string", "null"]
description: Stack name (when target_type is `stack`).
node_id:
type: ["integer", "null"]
description: Target node ID (when target_type is `stack`).
action:
type: string
enum: [restart, snapshot, prune]
cron_expression:
type: string
description: Standard cron expression (5 fields).
example: "0 3 * * *"
enabled:
type: integer
enum: [0, 1]
created_by:
type: string
created_at:
type: integer
description: Unix timestamp (seconds).
updated_at:
type: integer
description: Unix timestamp (seconds).
last_run_at:
type: ["integer", "null"]
next_run_at:
type: ["integer", "null"]
last_status:
type: ["string", "null"]
last_error:
type: ["string", "null"]
prune_targets:
type: ["string", "null"]
description: JSON-stringified array of prune targets (containers, images, networks, volumes).
target_services:
type: ["string", "null"]
description: JSON-stringified array of service names to restart.
prune_label_filter:
type: ["string", "null"]
description: Docker label filter for prune operations.
ScheduledTaskRun:
type: object
required: [id, task_id, started_at, status, triggered_by]
properties:
id:
type: integer
task_id:
type: integer
started_at:
type: integer
description: Unix timestamp (seconds).
completed_at:
type: ["integer", "null"]
triggered_by:
type: string
enum: [scheduled, manual]
status:
type: string
enum: [pending, running, success, failed]
output:
type: ["string", "null"]
error:
type: ["string", "null"]
Registry:
type: object
properties:
id:
type: integer
name:
type: string
example: GitHub Container Registry
url:
type: string
example: ghcr.io
type:
type: string
enum: [dockerhub, ghcr, ecr, custom]
username:
type: string
aws_region:
type: ["string", "null"]
description: AWS region (only present for ECR registries).
created_at:
type: integer
description: Unix timestamp (seconds).
RegistryCreate:
type: object
required: [name, url, type, username, secret]
properties:
name:
type: string
maxLength: 100
example: GitHub Container Registry
url:
type: string
maxLength: 500
example: ghcr.io
type:
type: string
enum: [dockerhub, ghcr, ecr, custom]
username:
type: string
example: my-user
secret:
type: string
description: Password, token, or access key. Write-only — never returned in GET responses.
aws_region:
type: string
description: Required when `type` is `ecr`.
example: us-east-1
ImageUpdateStatus:
type: object
properties:
stack_name:
type: string
description: Name of the stack.
has_updates:
type: integer
enum: [0, 1]
description: Whether any images in this stack have newer versions available.
last_checked:
type: ["integer", "null"]
description: Unix timestamp of the last check.
responses:
Unauthorized:
description: Authentication required. Provide a valid Bearer token.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error: "Authentication required"
Forbidden:
description: Insufficient permissions or license tier.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error: "This feature requires Sencho Pro."
code: "PRO_REQUIRED"
NotFound:
description: Resource not found.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
InternalError:
description: Internal server error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
paths:
# ── Health ──────────────────────────────────────────────
/api/health:
get:
operationId: getHealth
tags: [Health]
summary: Health check
description: Returns instance health status and uptime. No authentication required. Useful for uptime monitors and Docker HEALTHCHECK.
security: []
responses:
"200":
description: Instance is healthy.
content:
application/json:
schema:
type: object
required: [status, uptime]
properties:
status:
type: string
example: ok
uptime:
type: number
description: Process uptime in seconds.
/api/meta:
get:
operationId: getMeta
tags: [Health]
summary: Instance metadata
description: Returns this Sencho instance's version and list of supported capabilities. No authentication required. Used by nodes to negotiate feature compatibility.
security: []
responses:
"200":
description: Instance metadata.
content:
application/json:
schema:
type: object
required: [version, capabilities]
properties:
version:
type: string
description: Sencho version (semver).
example: "0.32.0"
capabilities:
type: array
description: List of feature capabilities this instance supports.
items:
type: string
example: ["stacks", "containers", "fleet", "auto-updates", "host-console"]
/api/system/update:
post:
operationId: triggerSelfUpdate
tags: [Health]
summary: Trigger self-update
description: |
Instructs this Sencho instance to pull the latest Docker image and recreate its own container.
Returns 202 immediately; the actual update happens asynchronously after the response is sent.
Requires the instance to be deployed via Docker Compose with the Docker socket mounted.
responses:
"202":
description: Update initiated.
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: "Update initiated. The server will restart shortly."
"401":
$ref: "#/components/responses/Unauthorized"
"503":
description: Self-update not available (not running in Docker Compose).
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
# ── Stacks ──────────────────────────────────────────────
/api/stacks:
get:
operationId: listStacks
tags: [Stacks]
summary: List all stacks
description: Returns an array of stack directory names on the target node.
parameters:
- $ref: "#/components/parameters/nodeId"
- $ref: "#/components/parameters/nodeIdQuery"
responses:
"200":
description: Array of stack names.
content:
application/json:
schema:
type: array
items:
type: string
example: ["traefik", "portainer", "monitoring"]
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
post:
operationId: createStack
tags: [Stacks]
summary: Create a new stack
description: Creates a new stack directory with a default `compose.yaml` file.
parameters:
- $ref: "#/components/parameters/nodeId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [stackName]
properties:
stackName:
type: string
description: Stack name. Alphanumeric characters, hyphens, and underscores only.
pattern: "^[a-zA-Z0-9_-]+$"
example: my-new-stack
responses:
"201":
description: Stack created.
content:
application/json:
schema:
type: object
required: [message, name]
properties:
message:
type: string
example: Stack created successfully
name:
type: string
example: my-new-stack
"400":
description: Invalid stack name.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Stack already exists.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error: Stack already exists
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}:
get:
operationId: getStack
tags: [Stacks]
summary: Get stack compose file
description: Returns the raw `compose.yaml` content for the specified stack.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Raw compose.yaml content.
content:
text/plain:
schema:
type: string
"400":
description: Invalid stack name.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
put:
operationId: updateStack
tags: [Stacks]
summary: Update stack compose file
description: Overwrites the `compose.yaml` content for the specified stack. Requires `stack:edit` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [content]
properties:
content:
type: string
description: Full compose.yaml content.
responses:
"200":
description: Stack saved.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Stack saved successfully
"400":
description: Invalid stack name or content.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteStack
tags: [Stacks]
summary: Delete stack
description: Permanently deletes the stack directory and all its files. Requires `stack:delete` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Stack deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Stack deleted successfully
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/envs:
get:
operationId: getStackEnvFiles
tags: [Stacks]
summary: List env file paths
description: Returns the list of environment file paths referenced in the stack's compose file (`env_file` directives).
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: List of env file paths.
content:
application/json:
schema:
type: object
required: [envFiles]
properties:
envFiles:
type: array
items:
type: string
example: [".env", "config/database.env"]
"400":
description: Invalid stack name.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/env:
get:
operationId: getStackEnv
tags: [Stacks]
summary: Get env file content
description: Returns the content of an environment file. Defaults to `.env` if no `file` query parameter is specified.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
- name: file
in: query
required: false
description: Path to a specific env file (must be in the resolved env files list).
schema:
type: string
responses:
"200":
description: Raw env file content (KEY=VALUE format).
content:
text/plain:
schema:
type: string
"400":
description: Invalid stack name or disallowed file path.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"404":
description: Env file not found.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error: Env file not found
"500":
$ref: "#/components/responses/InternalError"
put:
operationId: updateStackEnv
tags: [Stacks]
summary: Update env file
description: Overwrites an environment file's content. Requires `stack:edit` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
- name: file
in: query
required: false
description: Path to a specific env file to update.
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [content]
properties:
content:
type: string
description: Full env file content (KEY=VALUE format).
responses:
"200":
description: Env file saved.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Env file saved successfully
"400":
description: Invalid input.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/containers:
get:
operationId: getStackContainers
tags: [Stacks]
summary: List stack containers
description: Returns all containers belonging to the specified stack.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Array of container objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Container"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/services:
get:
operationId: getStackServices
tags: [Stacks]
summary: List stack services
description: Returns the service names defined in the stack's compose file.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Array of service names.
content:
application/json:
schema:
type: array
items:
type: string
example: ["web", "db", "redis"]
"400":
description: Invalid stack name.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/deploy:
post:
operationId: deployStack
tags: [Stacks]
summary: Deploy stack
description: |
Runs `docker compose up -d` for the stack. On Pro tier, uses atomic deployment
with automatic rollback on failure. Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Stack deployed successfully.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Deployed successfully
"403":
$ref: "#/components/responses/Forbidden"
"500":
description: Deployment failed.
content:
application/json:
schema:
type: object
required: [error]
properties:
error:
type: string
rolledBack:
type: boolean
description: Whether the stack was automatically rolled back (Pro tier).
/api/stacks/{stackName}/down:
post:
operationId: downStack
tags: [Stacks]
summary: Tear down stack
description: Runs `docker compose down` for the stack, removing containers and networks. Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Command started.
content:
application/json:
schema:
type: object
required: [status]
properties:
status:
type: string
example: Command started
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/start:
post:
operationId: startStack
tags: [Stacks]
summary: Start stack containers
description: Starts all stopped containers in the stack via the Docker Engine API. Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Containers started.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: No containers found for this stack.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/stop:
post:
operationId: stopStack
tags: [Stacks]
summary: Stop stack containers
description: Stops all running containers in the stack via the Docker Engine API. Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Containers stopped.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: No containers found for this stack.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/restart:
post:
operationId: restartStack
tags: [Stacks]
summary: Restart stack containers
description: Restarts all containers in the stack via the Docker Engine API. Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Containers restarted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: No containers found for this stack.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/update:
post:
operationId: updateStackImages
tags: [Stacks]
summary: Pull and recreate stack
description: |
Pulls latest images and recreates containers (`docker compose pull && up -d`).
On Pro tier, uses atomic update with automatic rollback on failure.
Requires `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Update completed.
content:
application/json:
schema:
type: object
required: [status]
properties:
status:
type: string
example: Update completed
"403":
$ref: "#/components/responses/Forbidden"
"500":
description: Update failed.
content:
application/json:
schema:
type: object
required: [error]
properties:
error:
type: string
rolledBack:
type: boolean
/api/stacks/{stackName}/rollback:
post:
operationId: rollbackStack
tags: [Stacks]
summary: Rollback stack
description: Restores the stack to its previous deployment state. Requires Pro license and `stack:deploy` permission.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Stack rolled back.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Stack rolled back successfully.
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: No backup available.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error: No backup available for this stack.
"500":
$ref: "#/components/responses/InternalError"
/api/stacks/{stackName}/backup:
get:
operationId: getStackBackupStatus
tags: [Stacks]
summary: Check backup status
description: Returns whether a deployment backup exists for this stack and when it was created.
parameters:
- $ref: "#/components/parameters/stackName"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Backup status.
content:
application/json:
schema:
type: object
required: [exists]
properties:
exists:
type: boolean
timestamp:
type: ["integer", "null"]
description: Unix timestamp of the backup, or null if no backup exists.
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
# ── Containers ──────────────────────────────────────────
/api/containers:
get:
operationId: listContainers
tags: [Containers]
summary: List all containers
description: Returns all running containers on the target node.
parameters:
- $ref: "#/components/parameters/nodeId"
- $ref: "#/components/parameters/nodeIdQuery"
responses:
"200":
description: Array of container objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Container"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/containers/{id}/logs:
get:
operationId: streamContainerLogs
tags: [Containers]
summary: Stream container logs
description: |
Streams container logs as Server-Sent Events (SSE). The connection remains
open and pushes new log lines as `data:` events in real time.
parameters:
- $ref: "#/components/parameters/idPath"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: SSE log stream.
content:
text/event-stream:
schema:
type: string
description: Each event is a `data:` line containing a JSON-encoded log string.
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/containers/{id}/start:
post:
operationId: startContainer
tags: [Containers]
summary: Start container
description: Starts a stopped container. Requires admin role.
parameters:
- $ref: "#/components/parameters/idPath"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Container started.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Container started
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/containers/{id}/stop:
post:
operationId: stopContainer
tags: [Containers]
summary: Stop container
description: Stops a running container. Requires admin role.
parameters:
- $ref: "#/components/parameters/idPath"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Container stopped.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Container stopped
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/containers/{id}/restart:
post:
operationId: restartContainer
tags: [Containers]
summary: Restart container
description: Restarts a container. Requires admin role.
parameters:
- $ref: "#/components/parameters/idPath"
- $ref: "#/components/parameters/nodeId"
responses:
"200":
description: Container restarted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Container restarted
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
# ── API Tokens ──────────────────────────────────────────
/api/api-tokens:
post:
operationId: createApiToken
tags: [API Tokens]
summary: Create API token
description: |
Generates a new scoped API token. The full token is only returned in the creation response
and cannot be retrieved again. Requires Admiral license and admin role.
**Note:** API tokens cannot create other API tokens.
responses:
"201":
description: Token created. The `token` field contains the full JWT — save it now, it won't be shown again.
content:
application/json:
schema:
type: object
required: [id, token]
properties:
id:
type: integer
token:
type: string
description: Full JWT token. Store securely — this is the only time it's returned.
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, scope]
properties:
name:
type: string
description: Human-readable token name.
maxLength: 100
example: CI/CD Deploy Token
scope:
type: string
description: |
Permission scope:
- `read-only` — GET requests only
- `deploy-only` — Read + stack deploy/stop/restart operations
- `full-admin` — All operations (except license, user, and token management)
enum: [read-only, deploy-only, full-admin]
expires_in:
type: ["integer", "null"]
description: Token lifetime in days. Use `null` for no expiry.
enum: [30, 60, 90, 365, null]
example: 90
get:
operationId: listApiTokens
tags: [API Tokens]
summary: List API tokens
description: |
Returns all API tokens for the current user. Token hashes are never exposed.
Requires Admiral license and admin role.
**Note:** API tokens cannot list other API tokens.
responses:
"200":
description: Array of token metadata.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ApiToken"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/api-tokens/{id}:
delete:
operationId: revokeApiToken
tags: [API Tokens]
summary: Revoke API token
description: |
Permanently revokes an API token. Users can only revoke their own tokens.
Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Token revoked.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"400":
description: Invalid token ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
# ── Webhooks ────────────────────────────────────────────
/api/webhooks:
get:
operationId: listWebhooks
tags: [Webhooks]
summary: List webhooks
description: Returns all configured webhooks with masked secrets. Requires Pro license.
responses:
"200":
description: Array of webhook objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Webhook"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
post:
operationId: createWebhook
tags: [Webhooks]
summary: Create webhook
description: |
Creates a new webhook for a stack. The webhook secret is auto-generated and only
returned in the creation response. Requires Pro license and admin role.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, stack_name, action]
properties:
name:
type: string
example: GitHub Deploy Hook
stack_name:
type: string
description: Target stack name.
example: my-app
action:
type: string
enum: [deploy, restart, stop, start, pull]
description: Action to execute when the webhook is triggered.
enabled:
type: boolean
default: true
responses:
"201":
description: Webhook created. The `secret` field is the HMAC signing key — save it now.
content:
application/json:
schema:
type: object
required: [id, secret]
properties:
id:
type: integer
secret:
type: string
description: HMAC-SHA256 signing secret. Store securely — this is the only time it's returned in full.
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/webhooks/{id}:
put:
operationId: updateWebhook
tags: [Webhooks]
summary: Update webhook
description: Updates webhook configuration. Requires Pro license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
stack_name:
type: string
action:
type: string
enum: [deploy, restart, stop, start, pull]
enabled:
type: boolean
responses:
"200":
description: Webhook updated.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteWebhook
tags: [Webhooks]
summary: Delete webhook
description: Permanently deletes a webhook. Requires Pro license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Webhook deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/webhooks/{id}/history:
get:
operationId: getWebhookHistory
tags: [Webhooks]
summary: Get webhook execution history
description: Returns the execution log for a webhook. Requires Pro license.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Array of execution records.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/WebhookExecution"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/webhooks/{id}/trigger:
post:
operationId: triggerWebhook
tags: [Webhooks]
summary: Trigger webhook
description: |
Externally triggers a webhook action. This endpoint is public but requires a valid
HMAC-SHA256 signature in the `X-Webhook-Signature` header.
Compute the signature as: `sha256=` + HMAC-SHA256(raw_request_body, webhook_secret).
security:
- webhookSignature: []
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
action:
type: string
description: Override the default webhook action.
responses:
"202":
description: Webhook accepted and action queued.
content:
application/json:
schema:
type: object
required: [message, action]
properties:
message:
type: string
example: Webhook accepted
action:
type: string
example: deploy
"401":
description: Missing or invalid signature.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: Webhook not found or disabled.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
# ── Nodes ───────────────────────────────────────────────
/api/nodes:
get:
operationId: listNodes
tags: [Nodes]
summary: List all nodes
description: Returns all registered nodes (local and remote).
responses:
"200":
description: Array of node objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Node"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
post:
operationId: createNode
tags: [Nodes]
summary: Register a new node
description: |
Adds a new local or remote node. Remote nodes require an API URL pointing to
another Sencho instance and an API token for authentication.
Requires `node:manage` permission.
**Note:** API tokens cannot manage nodes.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, type]
properties:
name:
type: string
example: production-server
type:
type: string
enum: [local, remote]
compose_dir:
type: string
description: Base directory for Compose stacks (defaults to `/app/compose`).
is_default:
type: boolean
description: Set as the default node.
api_url:
type: string
description: Remote Sencho instance URL (required for remote nodes).
example: https://sencho.example.com:3000
api_token:
type: string
description: API token for authenticating with the remote Sencho instance.
responses:
"200":
description: Node created.
content:
application/json:
schema:
type: object
required: [success, id]
properties:
success:
type: boolean
id:
type: integer
description: New node ID.
warning:
type: string
description: Warning if the remote URL uses plain HTTP.
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"409":
description: Node name already exists.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/nodes/{id}:
get:
operationId: getNode
tags: [Nodes]
summary: Get node details
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Node object.
content:
application/json:
schema:
$ref: "#/components/schemas/Node"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
put:
operationId: updateNode
tags: [Nodes]
summary: Update node
description: Updates node configuration. Requires `node:manage` permission.
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
compose_dir:
type: string
is_default:
type: boolean
api_url:
type: string
api_token:
type: string
responses:
"200":
description: Node updated.
content:
application/json:
schema:
type: object
required: [success]
properties:
success:
type: boolean
warning:
type: string
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteNode
tags: [Nodes]
summary: Delete node
description: Removes a node from the fleet. Requires `node:manage` permission.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Node deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/nodes/{id}/test:
post:
operationId: testNodeConnection
tags: [Nodes]
summary: Test node connection
description: Tests connectivity to a node. For remote nodes, pings the remote Sencho instance's health endpoint.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Connection test result.
content:
application/json:
schema:
type: object
required: [success]
properties:
success:
type: boolean
message:
type: string
error:
type: string
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/nodes/{id}/meta:
get:
operationId: getNodeMeta
tags: [Nodes]
summary: Get node capabilities
description: "Returns the version and supported capabilities for a specific node. For local nodes, returns this instance's own metadata. For remote nodes, relays the response from the remote instance's `/api/meta` endpoint. Returns `{ version: null, capabilities: [] }` if the remote node is offline or doesn't support the meta endpoint."
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Node capability metadata.
content:
application/json:
schema:
type: object
required: [version, capabilities]
properties:
version:
type: string
nullable: true
description: Sencho version of the node, or null if unavailable.
example: "0.31.0"
capabilities:
type: array
description: List of feature capabilities the node supports. Empty array if unavailable.
items:
type: string
example: ["stacks", "containers", "fleet"]
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
# ── Fleet ───────────────────────────────────────────────
/api/fleet/overview:
get:
operationId: getFleetOverview
tags: [Fleet]
summary: Fleet overview
description: Returns an aggregated overview of all nodes including status, container stats, and stack counts.
responses:
"200":
description: Array of fleet node overviews.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/FleetNodeOverview"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/fleet/node/{nodeId}/stacks:
get:
operationId: getFleetNodeStacks
tags: [Fleet]
summary: List stacks on a fleet node
description: Returns stack names from a specific fleet node. Requires Pro license.
parameters:
- name: nodeId
in: path
required: true
schema:
type: integer
responses:
"200":
description: Array of stack names.
content:
application/json:
schema:
type: array
items:
type: string
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
"502":
description: Failed to reach remote node.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
description: Remote node not configured.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/api/fleet/node/{nodeId}/stacks/{stackName}/containers:
get:
operationId: getFleetNodeStackContainers
tags: [Fleet]
summary: List containers in a fleet node stack
description: Returns containers for a specific stack on a specific fleet node. Requires Pro license.
parameters:
- name: nodeId
in: path
required: true
schema:
type: integer
- $ref: "#/components/parameters/stackName"
responses:
"200":
description: Array of container objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Container"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
"503":
description: Remote node not configured.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/api/fleet/update-status:
get:
operationId: getFleetUpdateStatus
tags: [Fleet]
summary: Fleet update status
description: Returns version comparison and active update status for all nodes. Compares each node's version against the gateway's version.
responses:
"200":
description: Update status for all nodes.
content:
application/json:
schema:
type: object
properties:
nodes:
type: array
items:
type: object
properties:
nodeId:
type: integer
name:
type: string
type:
type: string
enum: [local, remote]
version:
type: string
nullable: true
latestVersion:
type: string
updateAvailable:
type: boolean
updateStatus:
type: string
nullable: true
enum: [updating, completed, timeout, failed, null]
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/ProRequired"
/api/fleet/nodes/{nodeId}/update:
post:
operationId: triggerNodeUpdate
tags: [Fleet]
summary: Trigger node update
description: Initiates a self-update on the specified node. For remote nodes, sends the update command via the proxy. For local nodes, triggers the update directly.
parameters:
- name: nodeId
in: path
required: true
schema:
type: integer
responses:
"202":
description: Update initiated.
content:
application/json:
schema:
type: object
properties:
message:
type: string
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/ProRequired"
"404":
description: Node not found.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Update already in progress.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
description: Self-update not available on the target node.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/api/fleet/update-all:
post:
operationId: triggerFleetUpdateAll
tags: [Fleet]
summary: Update all outdated nodes
description: Triggers self-update on all remote nodes running an older version than the gateway. Local nodes are excluded from bulk updates.
responses:
"202":
description: Bulk update initiated.
content:
application/json:
schema:
type: object
properties:
updating:
type: array
items:
type: string
description: Names of nodes where update was triggered.
skipped:
type: array
items:
type: string
description: Names of nodes that were skipped.
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/ProRequired"
/api/fleet/snapshots:
post:
operationId: createFleetSnapshot
tags: [Fleet]
summary: Create fleet snapshot
description: Creates a point-in-time backup of all compose files across all nodes. Requires Pro license and admin role.
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
description:
type: string
description: Optional description for the snapshot.
example: Pre-migration backup
responses:
"201":
description: Snapshot created.
content:
application/json:
schema:
$ref: "#/components/schemas/FleetSnapshot"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
get:
operationId: listFleetSnapshots
tags: [Fleet]
summary: List fleet snapshots
description: Returns paginated fleet snapshots. Requires Pro license.
parameters:
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 100
- name: offset
in: query
schema:
type: integer
default: 0
responses:
"200":
description: Paginated snapshot list.
content:
application/json:
schema:
type: object
required: [snapshots, total]
properties:
snapshots:
type: array
items:
$ref: "#/components/schemas/FleetSnapshot"
total:
type: integer
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/fleet/snapshots/{id}:
get:
operationId: getFleetSnapshot
tags: [Fleet]
summary: Get snapshot details
description: Returns full snapshot details including all captured files grouped by node and stack. Requires Pro license.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Snapshot with file contents.
content:
application/json:
schema:
$ref: "#/components/schemas/FleetSnapshotDetail"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteFleetSnapshot
tags: [Fleet]
summary: Delete snapshot
description: Permanently deletes a fleet snapshot. Requires Pro license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Snapshot deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/fleet/snapshots/{id}/restore:
post:
operationId: restoreFleetSnapshot
tags: [Fleet]
summary: Restore from snapshot
description: Restores a specific stack on a specific node from the snapshot. Optionally redeploys after restore. Requires Pro license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [nodeId, stackName]
properties:
nodeId:
type: integer
description: Target node ID to restore to.
stackName:
type: string
description: Stack to restore.
redeploy:
type: boolean
default: false
description: Whether to redeploy the stack after restoring files.
responses:
"200":
description: Stack restored.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessMessage"
example:
message: Stack restored successfully.
"400":
description: Missing required fields.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
# ── Scheduled Tasks ─────────────────────────────────────
/api/scheduled-tasks:
get:
operationId: listScheduledTasks
tags: [Scheduled Tasks]
summary: List scheduled tasks
description: Returns all scheduled tasks. Requires Admiral license and admin role.
responses:
"200":
description: Array of scheduled task objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ScheduledTask"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
post:
operationId: createScheduledTask
tags: [Scheduled Tasks]
summary: Create scheduled task
description: |
Creates a new recurring task. Action-target rules:
- `restart` requires `target_type: stack` (with `target_id` and `node_id`)
- `snapshot` requires `target_type: fleet`
- `prune` requires `target_type: system`
Requires Admiral license and admin role.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, target_type, action, cron_expression]
properties:
name:
type: string
example: Nightly restart
target_type:
type: string
enum: [stack, fleet, system]
target_id:
type: string
description: Stack name (required when target_type is `stack`).
node_id:
type: integer
description: Target node ID (required when target_type is `stack`).
action:
type: string
enum: [restart, snapshot, prune]
cron_expression:
type: string
description: Standard 5-field cron expression.
example: "0 3 * * *"
enabled:
type: boolean
default: true
prune_targets:
type: array
items:
type: string
enum: [containers, images, networks, volumes]
description: Resources to prune (only for `prune` action).
target_services:
type: array
items:
type: string
description: Specific services to restart (only for `restart` action).
prune_label_filter:
type: string
description: Docker label filter for prune operations.
responses:
"201":
description: Task created.
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledTask"
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/scheduled-tasks/{id}:
get:
operationId: getScheduledTask
tags: [Scheduled Tasks]
summary: Get scheduled task
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Scheduled task object.
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledTask"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
put:
operationId: updateScheduledTask
tags: [Scheduled Tasks]
summary: Update scheduled task
description: Updates task configuration. Same validation rules as creation apply. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
target_type:
type: string
enum: [stack, fleet, system]
target_id:
type: string
node_id:
type: integer
action:
type: string
enum: [restart, snapshot, prune]
cron_expression:
type: string
enabled:
type: boolean
prune_targets:
type: array
items:
type: string
target_services:
type: array
items:
type: string
prune_label_filter:
type: string
responses:
"200":
description: Task updated.
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledTask"
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteScheduledTask
tags: [Scheduled Tasks]
summary: Delete scheduled task
description: Permanently deletes a scheduled task. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Task deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/scheduled-tasks/{id}/toggle:
patch:
operationId: toggleScheduledTask
tags: [Scheduled Tasks]
summary: Toggle task enabled/disabled
description: Flips the enabled state of a scheduled task. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Task toggled. Returns updated task.
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledTask"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/scheduled-tasks/{id}/run:
post:
operationId: runScheduledTask
tags: [Scheduled Tasks]
summary: Run task immediately
description: Executes the scheduled task immediately, regardless of its cron schedule. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Task executed. Returns updated task with `last_run_at`.
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledTask"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/scheduled-tasks/{id}/runs:
get:
operationId: listScheduledTaskRuns
tags: [Scheduled Tasks]
summary: List task execution history
description: Returns paginated execution history for a scheduled task. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
- name: limit
in: query
schema:
type: integer
default: 50
- name: offset
in: query
schema:
type: integer
default: 0
responses:
"200":
description: Array of task run records.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ScheduledTaskRun"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/scheduled-tasks/{id}/runs/export:
get:
operationId: exportScheduledTaskRuns
tags: [Scheduled Tasks]
summary: Export task history as CSV
description: Downloads the execution history for a scheduled task as a CSV file. Requires Admiral license and admin role.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: CSV file download.
content:
text/csv:
schema:
type: string
description: "CSV with columns: Timestamp, Source, Status, Duration (s), Details"
"400":
description: Invalid task ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
# ── Registries ──────────────────────────────────────────
/api/registries:
get:
operationId: listRegistries
tags: [Registries]
summary: List registries
description: |
Returns all configured private container registries. Secrets are never included in the response.
Requires Admiral license and admin role. API tokens receive `SCOPE_DENIED`.
responses:
"200":
description: Array of registry objects.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Registry"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
post:
operationId: createRegistry
tags: [Registries]
summary: Create registry
description: |
Adds a new private container registry. The secret is encrypted at rest using AES-256-GCM.
Requires Admiral license and admin role. API tokens receive `SCOPE_DENIED`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegistryCreate"
responses:
"201":
description: Registry created.
content:
application/json:
schema:
type: object
required: [id]
properties:
id:
type: integer
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
/api/registries/{id}:
put:
operationId: updateRegistry
tags: [Registries]
summary: Update registry
description: |
Updates an existing registry. All fields are optional — only provided fields are changed.
Requires Admiral license and admin role. API tokens receive `SCOPE_DENIED`.
parameters:
- $ref: "#/components/parameters/idPath"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegistryCreate"
responses:
"200":
description: Registry updated.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"400":
description: Validation error.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
delete:
operationId: deleteRegistry
tags: [Registries]
summary: Delete registry
description: |
Removes a registry and its encrypted credentials.
Requires Admiral license and admin role. API tokens receive `SCOPE_DENIED`.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Registry deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessBoolean"
"400":
description: Invalid registry ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalError"
/api/registries/{id}/test:
post:
operationId: testRegistry
tags: [Registries]
summary: Test registry connection
description: |
Tests connectivity and authentication against a configured registry.
Requires Admiral license and admin role. API tokens receive `SCOPE_DENIED`.
parameters:
- $ref: "#/components/parameters/idPath"
responses:
"200":
description: Test result.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
"400":
description: Invalid registry ID.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
$ref: "#/components/responses/Forbidden"
"500":
$ref: "#/components/responses/InternalError"
# ── Image Updates ───────────────────────────────────────
/api/image-updates:
get:
operationId: getImageUpdates
tags: [Image Updates]
summary: Get image update status
description: Returns the update availability status for all stacks.
responses:
"200":
description: Array of update status objects per stack.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ImageUpdateStatus"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
$ref: "#/components/responses/InternalError"
/api/image-updates/refresh:
post:
operationId: refreshImageUpdates
tags: [Image Updates]
summary: Trigger image update check
description: |
Triggers a background check for newer image versions across all stacks.
Rate limited to one refresh per 10 minutes. Requires admin role.
responses:
"200":
description: Refresh started.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
example: Image update check started in background.
"401":
$ref: "#/components/responses/Unauthorized"
"429":
description: Rate limited — wait at least 10 minutes between refreshes.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"500":
$ref: "#/components/responses/InternalError"
/api/image-updates/status:
get:
operationId: getImageUpdateCheckStatus
tags: [Image Updates]
summary: Check if update scan is running
description: Returns whether an image update check is currently in progress.
responses:
"200":
description: Check status.
content:
application/json:
schema:
type: object
required: [checking]
properties:
checking:
type: boolean
description: "`true` if a scan is currently running."
"401":
$ref: "#/components/responses/Unauthorized"