Files
Containr/docs/api/openapi.yaml
T
Tomáš DvořákandDevin bc93c83cf9 feat(scheduling): multi-node service placement + remote lifecycle (#54)
* feat(scheduling): multi-node service placement + remote container lifecycle

services.node_id pins a service to a node agent: explicit id, "auto"
(least-loaded online node), or "local"/empty for the local Docker host.

- DeploymentEngine gains a NodeRunner seam; ReconcileService routes
  pinned services to the agent's command queue (create_container with
  image/env/command/ports/volumes/labels/resource limits), tracked in
  container_instances with deterministic per-replica ids.
- Stop/start/restart/delete fan out to the pinned node — no more leaked
  remote containers on service delete.
- Agent create_container is idempotent (rm -f first) and honors restart
  policy, labels, memory/cpus, published+ephemeral ports, volumes, env.
- GET /nodes/options exposes id/name/status to authed users; full agent
  management stays admin-only.
- CLI services create/update --node, MCP node_id docs, OpenAPI
  node_id/node_name + /nodes/options, service-detail Placement section.

Ceilings: remote nodes run registry-pulled images only — git builds,
Traefik domains, and remote sleep detection stay local until
build-on-node and per-node ingress land.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* feat(scheduling): node cordon/drain + schedulable gate

- node_agents.schedulable column; "auto" placement and explicit pins skip
  cordoned nodes; already-pinned services keep running (reconcile is
  unaffected — cordon is not eviction).
- POST /agents/:id/cordon|uncordon|drain (admin). Drain cordons, removes
  every service container via the agent queue, and clears the services'
  pins so they redeploy on the local host. Requires the node online —
  an offline node can't acknowledge removals.
- CLI nodes cordon|uncordon|drain (drain confirm-gated), MCP
  containr_nodes_cordon|uncordon|drain, OpenAPI paths + schedulable
  field, node-detail page cordon badge + drain/cordon controls.
- Fix: re-registering an agent no longer resets auto_prune.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* feat(scheduling): remote registry pulls + post-run health check

- Dispatch payload carries the project owner's registry credentials for
  the image host; the agent docker-logins for the pull and logs out
  after, so private images deploy to remote nodes.
- Completed command payloads get their registry password scrubbed —
  secrets don't linger in agent_commands rows.
- Agent verifies the container is still running ~1.5s after docker run;
  crash-loops now fail the deployment with the container's last log
  lines instead of reporting "running" optimistically.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-09 16:19:12 +02:00

9890 lines
261 KiB
YAML

openapi: 3.0.3
info:
title: Containr API
description: |
Self-hosted PaaS on Proxmox - Railway-like platform for container orchestration and deployment.
## Overview
Containr provides a comprehensive platform for deploying, managing, and scaling containerized applications on Proxmox infrastructure. This API allows you to manage projects, services, deployments, databases, and more through a RESTful interface.
## Authentication
The API accepts three credentials in the Authorization header:
`Authorization: Bearer <jwt>` (UI sessions), a Better Auth session cookie, or a
personal access token `cnp_...` (CLI/MCP/agents). PAT scopes: `read` allows only
GET/HEAD/OPTIONS; `write` everything except admin routes; `admin` requires a
platform-admin owner.
## Errors
Error responses use `{"error": "human message", "code": "MACHINE_CODE"}`. Stable
codes: `UNAUTHENTICATED`, `INVALID_TOKEN`, `FORBIDDEN`, `ADMIN_REQUIRED`,
`SCOPE_INSUFFICIENT`, `NOT_FOUND`, `VALIDATION`, `CONFLICT`, `INTERNAL`,
`DEPENDENCY_UNAVAILABLE`, `IDEMPOTENCY_IN_PROGRESS`.
## Idempotency
POST endpoints accept an `Idempotency-Key` header. The first response is replayed
for repeated keys within 24h (scoped to the caller and path); a concurrent duplicate
receives `409 IDEMPOTENCY_IN_PROGRESS`. Safe for clients to always send a UUID.
## Pagination
List endpoints accept `?limit=` plus either `?page=` (legacy) or `?cursor=`
(preferred — pass `pagination.next_cursor` from the previous response verbatim).
Invalid cursors fail soft to the first page.
## Base URL
```
https://your-containr-domain.com/api/v1
```
version: 1.0.0
contact:
name: Containr Documentation
url: https://github.com/your-org/containr
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: http://localhost:8080/api/v1
description: Development server
- url: https://your-containr-domain.com/api/v1
description: Production server
paths:
# Health Check
/health:
servers:
- url: http://localhost:8080
get:
tags:
- Health
summary: Health check endpoint
description: 'Served at the root, outside /api/v1. Returns dependency status: {"checks":{"database":"ok","redis":"ok"},"service":"containr-api","status":"ok"}'
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthResponse'
# Authentication
/auth/login:
post:
tags:
- Authentication
summary: User login
description: Authenticate user and return JWT token
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Login successful
content:
application/json:
schema:
$ref: '#/components/schemas/LoginResponse'
'401':
description: Invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/auth/register:
post:
tags:
- Authentication
summary: User registration
description: Register a new user account
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterRequest'
responses:
'201':
description: Registration successful
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# User Management
/user/profile:
get:
tags:
- User
summary: Get user profile
description: Retrieve current user's profile information
security:
- bearerAuth: []
responses:
'200':
description: Profile retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- User
summary: Update user profile
description: Update current user's profile information
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: Profile updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/user/tokens:
get:
tags:
- User
summary: List personal access tokens
description: Returns the caller's non-revoked personal access token metadata. Token values and hashes are never returned.
security:
- bearerAuth: []
responses:
'200':
description: Token list
content:
application/json:
schema:
type: object
properties:
tokens:
type: array
items:
$ref: '#/components/schemas/UserToken'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- User
summary: Create personal access token
description: Issues a `cnp_` bearer token for CLI/MCP/agent authentication. The raw token is returned exactly once and never stored — only its SHA-256 hash persists. Admin-scope tokens require a platform admin account.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserTokenRequest'
responses:
'201':
description: Token created; raw value returned once
content:
application/json:
schema:
$ref: '#/components/schemas/UserTokenCreated'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Admin scope requires platform admin
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/user/tokens/{id}:
delete:
tags:
- User
summary: Revoke personal access token
description: Marks one of the caller's tokens as revoked. Clients presenting it are rejected from then on.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Token revoked
content:
application/json:
schema:
type: object
properties:
message:
type: string
'404':
description: Token not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Projects
/projects:
get:
tags:
- Projects
summary: List projects
description: Retrieve all projects accessible to the current user
security:
- bearerAuth: []
parameters:
- name: page
in: query
description: Page number for pagination (legacy — prefer cursor)
schema:
type: integer
default: 1
- name: limit
in: query
description: Number of items per page
schema:
type: integer
default: 20
- name: cursor
in: query
description: Opaque cursor from a previous response's pagination.next_cursor
schema:
type: string
- name: search
in: query
description: Search term to filter projects
schema:
type: string
responses:
'200':
description: Projects retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectsResponse'
post:
tags:
- Projects
summary: Create project
description: Create a new project
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateProjectRequest'
responses:
'201':
description: Project created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects/{id}:
get:
tags:
- Projects
summary: Get project
description: Retrieve a specific project by ID
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Project ID
schema:
type: string
responses:
'200':
description: Project retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Projects
summary: Update project
description: Update a specific project
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Project ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateProjectRequest'
responses:
'200':
description: Project updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- Projects
summary: Delete project
description: Delete a specific project
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Project ID
schema:
type: string
responses:
'204':
description: Project deleted successfully
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Services
/projects/{id}/services:
get:
tags:
- Services
summary: List project services
description: Retrieve all services in a project
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Project ID
schema:
type: string
responses:
'200':
description: Services retrieved successfully
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Service'
post:
tags:
- Services
summary: Create service
description: Create a new service in a project
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Project ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateServiceRequest'
responses:
'201':
description: Service created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Service'
/services/{id}:
get:
tags:
- Services
summary: Get service
description: Retrieve a specific service
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
responses:
'200':
description: Service retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Service'
put:
tags:
- Services
summary: Update service
description: Update a specific service
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateServiceRequest'
responses:
'200':
description: Service updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Service'
delete:
tags:
- Services
summary: Delete service
description: Delete a specific service
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
responses:
'204':
description: Service deleted successfully
/services/{id}/runtime:
get:
tags:
- Services
summary: Service runtime state
description: Live container state — replicas, URLs, aggregate status
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Runtime state
content:
application/json:
schema:
type: object
properties:
runtime:
type: object
properties:
desired:
type: integer
status:
type: string
enum: [running, degraded, stopped]
urls:
type: array
items:
type: string
description: Reachable service URLs; rewritten to the request Host for remote clients. Null/empty when nothing is published.
ports:
type: array
items:
type: integer
description: Host ports actually bound for replica 0+; persisted on the service so restarts reuse the same public port. Null/empty when nothing is published.
health:
type: string
enum: [healthy, unhealthy, unreachable]
description: Result of the backend's HTTP probe of the service on its project network. Omitted when the service declares no healthcheck path.
containers:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
state:
type: string
replica:
type: integer
/services/{id}/start:
post:
tags:
- Services
summary: Start service
description: Start all stopped replicas
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Service started
/services/{id}/stop:
post:
tags:
- Services
summary: Stop service
description: Stop all replicas without removing them
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Service stopped
/services/{id}/restart:
post:
tags:
- Services
summary: Restart service
description: Restart all replicas
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Service restarted
/services/{id}/sleep:
post:
tags:
- Services
summary: Sleep service
description: Scale the service to zero immediately. When it has public domains a wake placeholder holds the route and resumes the service on the next request.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'202':
description: Sleep initiated
/services/{id}/wake:
post:
tags:
- Services
summary: Wake service
description: Reconcile a sleeping service back to running on demand
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'202':
description: Wake initiated
/services/{id}/env-check:
get:
tags:
- Services
summary: Environment diagnostics
description: Reports empty variables, unresolved ${{service.KEY}} references, and secrets whose stored ciphertext fails to decrypt. Values are never returned.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Diagnostic result
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
unresolved:
type: array
items:
type: string
empty:
type: array
items:
type: string
unreadable:
type: array
items:
type: string
/services/{id}/terminal:
get:
tags:
- Services
summary: Interactive terminal (WebSocket)
description: >-
Upgrades to a WebSocket bridged to a `docker exec` PTY in the
service's running container (bash if present, else sh).
Cookie/bearer auth as usual.
Client→server JSON frames: `{"type":"stdin","data":"..."}`,
`{"type":"resize","cols":N,"rows":N}`.
Server→client frames: `{"type":"stdout","data":"..."}`,
`{"type":"exit","code":N}`, `{"type":"error","message":"..."}`.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'101':
description: Switching protocols — WebSocket session established
'404':
description: Service not found or not visible
'409':
description: Service has no running container
'503':
description: Docker unavailable
/internal/wake/{id}:
get:
tags:
- Services
summary: Wake callback (internal)
description: Unauthenticated wake endpoint hit by the busybox wake placeholder while a slept service resumes. Idempotent and non-destructive.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'202':
description: Wake accepted
'404':
description: Service not found
/services/{id}/redeploy:
post:
tags:
- Services
summary: Redeploy service
description: Re-apply the current spec — pulls the image for image-sourced services, reuses the last deployed image otherwise
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Reconciled runtime state
/services/{id}/clone:
post:
tags:
- Services
summary: Clone service
description: Duplicates config, volumes, domains, access gates, builder settings, and variables into the same or another project. Containers are not cloned — the copy starts stopped.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Name for the clone (default "<name>-copy")
project_id:
type: string
format: uuid
description: Target project (default same project; caller must own it)
environment:
type: string
enum: [production, preview, development]
responses:
'201':
description: Clone created
content:
application/json:
schema:
type: object
properties:
service_id:
type: string
format: uuid
name:
type: string
message:
type: string
'409':
description: Name already exists in target project
/services/{id}/move:
post:
tags:
- Services
summary: Move service
description: Re-parents the service to another project the caller owns. Variables, domains, and volumes follow the service; running containers keep running and join the new project's network on next deploy.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [project_id]
properties:
project_id:
type: string
format: uuid
responses:
'200':
description: Service moved
'409':
description: Name conflict in target project
/registries:
get:
tags:
- Registries
summary: List registry credentials
description: Private-image pull credentials for the caller. Passwords are never returned — `has_password` signals presence.
security:
- bearerAuth: []
responses:
'200':
description: Registry list
content:
application/json:
schema:
type: object
properties:
registries:
type: array
items:
$ref: '#/components/schemas/Registry'
post:
tags:
- Registries
summary: Add registry credential
description: Credentials are matched by image host (e.g. ghcr.io, registry.example.com, docker.io for Docker Hub) on prebuilt-image deploys. Password stored encrypted at rest.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegistryRequest'
responses:
'201':
description: Registry created
'409':
description: A registry for this host already exists
/registries/{id}:
put:
tags:
- Registries
summary: Update registry credential
description: Empty password keeps the stored credential — delete and recreate to remove a password.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegistryRequest'
responses:
'200':
description: Registry updated
'404':
description: Registry not found
delete:
tags:
- Registries
summary: Remove registry credential
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Registry removed
'404':
description: Registry not found
/backup-targets:
get:
tags:
- BackupTargets
summary: List backup targets
description: S3-compatible archive destinations for the caller. Secret keys are never returned — `has_credentials` signals presence.
security:
- bearerAuth: []
responses:
'200':
description: Backup target list
content:
application/json:
schema:
type: object
properties:
backup_targets:
type: array
items:
$ref: '#/components/schemas/BackupTarget'
post:
tags:
- BackupTargets
summary: Register a backup target
description: The bucket is probed (BucketExists) before storing — typos and bad credentials fail at registration. Keys are stored encrypted at rest.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BackupTargetRequest'
responses:
'201':
description: Backup target created
'400':
description: Validation error or connection check failed
/backup-targets/{id}:
put:
tags:
- BackupTargets
summary: Update a backup target
description: Empty access_key/secret_key keep the stored pair — delete and recreate to remove credentials. Re-probed before saving.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BackupTargetRequest'
responses:
'200':
description: Backup target updated
'404':
description: Backup target not found
delete:
tags:
- BackupTargets
summary: Delete a backup target
description: Fails with 409 while databases still point at the target.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Backup target deleted
'409':
description: Databases still reference this target
/backup-targets/{id}/test:
post:
tags:
- BackupTargets
summary: Re-probe a backup target
description: Checks bucket access with the stored credentials. Always returns a probe result — `ok` false means unreachable or unauthorized.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Probe result
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
latency_ms:
type: integer
error:
type: string
/services/{id}/domains:
get:
tags:
- Services
summary: List service domains
description: All hostnames attached to the service; the default is mirrored to services.domain
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Domain list
content:
application/json:
schema:
type: object
properties:
domains:
type: array
items:
$ref: '#/components/schemas/ServiceDomain'
post:
tags:
- Services
summary: Attach a domain
description: Adds a hostname routed to the service via Traefik. The first domain becomes default automatically.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
properties:
domain:
type: string
is_default:
type: boolean
responses:
'201':
description: Domain attached
content:
application/json:
schema:
type: object
properties:
domain:
$ref: '#/components/schemas/ServiceDomain'
'409':
description: Domain already attached
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/services/{id}/domains/check:
get:
tags:
- Services
summary: DNS preflight
description: Resolves every attached domain and compares it to the expected target (app_settings.public_ip / PUBLIC_IP, or base_url host)
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Per-domain DNS status
content:
application/json:
schema:
type: object
properties:
domains:
type: array
items:
$ref: '#/components/schemas/DomainCheckResult'
/services/{id}/domains/{domain_id}:
delete:
tags:
- Services
summary: Detach a domain
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: domain_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Domain removed
/services/{id}/domains/{domain_id}/default:
post:
tags:
- Services
summary: Set the default domain
description: Marks the domain default and mirrors it to services.domain
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: domain_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Updated domain list
content:
application/json:
schema:
type: object
properties:
domains:
type: array
items:
$ref: '#/components/schemas/ServiceDomain'
/maintenance:
get:
tags:
- Services
summary: Maintenance page
description: Public HTML page Traefik redirects to while a service is in maintenance mode
/services/{id}/deployments:
get:
tags:
- Deployments
summary: List deployments
description: Retrieve recent deployments for a specific service
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 100
- name: cursor
in: query
description: Opaque cursor from a previous response's pagination.next_cursor
schema:
type: string
responses:
'200':
description: Deployments retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DeploymentListResponse'
post:
tags:
- Deployments
summary: Create deployment
description: Trigger a new deployment for a service
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDeploymentRequest'
responses:
'201':
description: Deployment created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Deployment'
/deployments:
get:
tags:
- Deployments
summary: List recent deployments
description: Latest deployments across all services owned by the caller — feeds the dashboard deploy feed
security:
- bearerAuth: []
parameters:
- name: limit
in: query
required: false
schema:
type: integer
default: 10
maximum: 50
- name: cursor
in: query
required: false
description: Opaque cursor from a previous response's pagination.next_cursor
schema:
type: string
responses:
'200':
description: Recent deployments
content:
application/json:
schema:
type: object
properties:
deployments:
type: array
items:
type: object
properties:
id:
type: string
service_id:
type: string
service_name:
type: string
project_name:
type: string
status:
type: string
image_name:
type: string
started_at:
type: string
nullable: true
completed_at:
type: string
nullable: true
created_at:
type: string
/deployments/{id}:
get:
tags:
- Deployments
summary: Get deployment
description: Retrieve a deployment with build/runtime details
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Deployment ID
schema:
type: string
responses:
'200':
description: Deployment retrieved successfully
content:
application/json:
schema:
type: object
properties:
deployment:
$ref: '#/components/schemas/Deployment'
/deployments/{id}/cancel:
post:
tags:
- Deployments
summary: Cancel a deployment
description: Cancel a queued or in-flight deployment. Queued deployments are marked cancelled immediately; running ones get their build/reconcile aborted and settle as 'cancelled' shortly after.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Deployment ID
schema:
type: string
responses:
'200':
description: Queued deployment cancelled
content:
application/json:
schema:
type: object
properties:
status: { type: string, example: cancelled }
'202':
description: Running deployment is cancelling
content:
application/json:
schema:
type: object
properties:
status: { type: string, example: cancelling }
'409':
description: Deployment already finished
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/deployments/{id}/rollback:
post:
tags:
- Deployments
summary: Rollback deployment
description: Create a rollback deployment from a previous deployment
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Deployment ID
schema:
type: string
responses:
'201':
description: Rollback initiated
content:
application/json:
schema:
$ref: '#/components/schemas/RollbackDeploymentResponse'
/services/{id}/logs:
get:
tags:
- Logs
summary: Get service logs
description: Retrieve service container logs
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
- name: follow
in: query
required: false
description: Stream logs continuously over SSE
schema:
type: boolean
default: false
- name: tail
in: query
required: false
description: Number of recent log lines to fetch
schema:
type: string
default: '100'
responses:
'200':
description: Service logs retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceLogsResponse'
/services/{id}/exec:
post:
tags:
- Services
summary: Execute command in service container
description: Runs a one-off shell command via docker exec and returns captured output. 30s ceiling, 64KB output cap. For debugging only.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Service ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- command
properties:
command:
type: string
description: Shell command (executed via sh -c)
maxLength: 4096
responses:
'200':
description: Command executed (check exit_code/error for failure)
content:
application/json:
schema:
type: object
properties:
output:
type: string
exit_code:
type: integer
error:
type: string
'400':
description: Invalid request
'404':
description: Service not found
'409':
description: No running container for this service
'503':
description: Docker unavailable
/deployments/{id}/logs:
get:
tags:
- Logs
summary: Get deployment logs
description: Retrieve build/runtime logs for a deployment
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Deployment ID
schema:
type: string
- name: type
in: query
required: false
description: Select log stream
schema:
type: string
enum: [all, build, runtime]
default: all
responses:
'200':
description: Deployment logs retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DeploymentLogsResponse'
# Builds
/builds:
get:
tags:
- Builds
summary: List builds
description: Retrieve builds with optional filtering and pagination
security:
- bearerAuth: []
parameters:
- name: project_id
in: query
description: Filter by project ID
schema:
type: string
- name: service_id
in: query
description: Filter by service ID
schema:
type: string
- name: status
in: query
description: Filter by build status
schema:
type: string
enum: [pending, running, success, failed, cancelled]
- name: page
in: query
description: 1-based page number
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
description: Number of items per page (max 100)
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: Builds retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/BuildListResponse'
post:
tags:
- Builds
summary: Start build
description: Start a new build
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/StartBuildRequest'
responses:
'201':
description: Build started successfully
content:
application/json:
schema:
$ref: '#/components/schemas/StartBuildResponse'
/builds/{id}:
get:
tags:
- Builds
summary: Get build status
description: Retrieve build status and details
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Build ID
schema:
type: string
responses:
'200':
description: Build status retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/BuildStatus'
/builds/{id}/cancel:
post:
tags:
- Builds
summary: Cancel build
description: Cancel an in-progress build
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Build ID
schema:
type: string
responses:
'200':
description: Build cancelled
content:
application/json:
schema:
$ref: '#/components/schemas/BuildCancelResponse'
/builds/{id}/logs:
get:
tags:
- Builds
summary: Get build logs
description: Retrieve build logs
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Build ID
schema:
type: string
- name: follow
in: query
required: false
description: Follow logs in realtime (currently returns same text output)
schema:
type: boolean
default: false
responses:
'200':
description: Build logs retrieved successfully
content:
text/plain:
schema:
type: string
# Templates
/templates:
get:
tags:
- Templates
summary: List templates
description: Retrieve service templates with optional category filter
security:
- bearerAuth: []
parameters:
- name: category
in: query
required: false
description: Filter templates by category
schema:
type: string
responses:
'200':
description: Templates retrieved successfully
content:
application/json:
schema:
type: object
properties:
templates:
type: array
items:
$ref: '#/components/schemas/ServiceTemplate'
post:
tags:
- Templates
summary: Create a user template
description: Create a user-owned template (JSON definition). Requires authentication; the caller becomes the template owner.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateWriteRequest'
responses:
'201':
description: Template created
content:
application/json:
schema:
type: object
properties:
template:
$ref: '#/components/schemas/ServiceTemplate'
/admin/overview:
get:
tags:
- Admin
summary: Platform overview
description: Admin-only aggregate statistics plus the pending project approval queue.
security:
- bearerAuth: []
responses:
'200':
description: Platform overview
content:
application/json:
schema:
type: object
properties:
stats:
type: object
additionalProperties:
type: integer
pending_projects:
type: array
items:
$ref: '#/components/schemas/Project'
/admin/users:
get:
tags:
- Admin
summary: List users
description: Admin-only listing of all platform users.
security:
- bearerAuth: []
responses:
'200':
description: Users retrieved
content:
application/json:
schema:
type: object
properties:
users:
type: array
items:
$ref: '#/components/schemas/AdminUser'
/admin/users/{id}:
patch:
tags:
- Admin
summary: Set user admin flag
description: Grant or revoke platform admin. Admins cannot revoke their own flag.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- is_admin
properties:
is_admin:
type: boolean
responses:
'200':
description: User updated
content:
application/json:
schema:
type: object
properties:
message:
type: string
/admin/users/{id}/impersonate:
post:
tags:
- Admin
summary: Impersonate a user
description: >-
Mint a 15-minute bearer token acting as the target user. Admin-only;
admin accounts cannot be impersonated and every mint is audit-logged.
The token carries an `impersonated_by` claim.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Impersonation token
content:
application/json:
schema:
type: object
properties:
token:
type: string
expires_at:
type: string
format: date-time
user:
type: object
properties:
id: {type: string}
email: {type: string}
name: {type: string}
'403':
description: Target is an admin account
/admin/projects/{id}:
patch:
tags:
- Admin
summary: Set project approval
description: Approve or unapprove a project for public listing.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- is_approved
properties:
is_approved:
type: boolean
responses:
'200':
description: Project updated
content:
application/json:
schema:
type: object
properties:
project:
$ref: '#/components/schemas/Project'
message:
type: string
/admin/volumes:
get:
tags:
- Admin
summary: List docker volumes
description: Returns the node's docker volume inventory with in-use flags. Admin only.
security:
- bearerAuth: []
responses:
'200':
description: Volume list
content:
application/json:
schema:
type: object
properties:
volumes:
type: array
items:
$ref: '#/components/schemas/VolumeInfo'
/admin/volumes/{name}:
delete:
tags:
- Admin
summary: Delete a docker volume
description: Removes an unused docker volume. Docker refuses in-use volumes — returned as 409.
security:
- bearerAuth: []
parameters:
- name: name
in: path
required: true
schema:
type: string
responses:
'200':
description: Volume deleted
'409':
description: Volume in use or removal failed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/templates/{id}:
get:
tags:
- Templates
summary: Get template
description: Retrieve a specific template with parsed config and variables
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: string
responses:
'200':
description: Template retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateDetailResponse'
put:
tags:
- Templates
summary: Update a user template
description: Update a user-created template. Official templates cannot be modified; only the owner or an admin may update.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateWriteRequest'
responses:
'200':
description: Template updated
content:
application/json:
schema:
type: object
properties:
template:
$ref: '#/components/schemas/ServiceTemplate'
delete:
tags:
- Templates
summary: Delete a user template
description: Delete a user-created template. Official templates cannot be deleted; only the owner or an admin may delete.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: string
responses:
'200':
description: Template deleted
content:
application/json:
schema:
type: object
properties:
message:
type: string
/templates/{id}/deploy:
post:
tags:
- Templates
summary: Create resource from template
description: |
Create a new resource in a project using a selected template.
For `database` templates, this creates a managed database service.
For v2 graph templates (config.services non-empty), this deploys
the entire service graph — databases first, then services in
dependency order — and returns `resource: stack` with a `created`
list. Deployments are enqueued for each service member.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DeployTemplateRequest'
responses:
'201':
description: Service created from template
content:
application/json:
schema:
$ref: '#/components/schemas/DeployTemplateResponse'
/templates/{id}/plan:
post:
tags:
- Templates
summary: Dry-resolve a template
description: |
Resolves a template without creating resources: variable merging,
`{{secret}}`/`{{random:N}}`/`{{VAR}}`/`{{VAR:-default}}` expression
expansion and `{{service.<key>.<prop>}}` references. Generated
secrets are returned masked — a real deploy regenerates them.
Returns `members` (with resolved environment), `missing_variables`
and `unresolved` reference names.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: string
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
project_id:
type: string
variables:
type: object
additionalProperties:
type: string
responses:
'200':
description: Resolved plan
content:
application/json:
schema:
type: object
properties:
members:
type: array
items:
$ref: '#/components/schemas/TemplatePlanMember'
missing_variables:
type: array
items:
type: string
unresolved:
type: array
items:
type: string
/templates/import/compose:
post:
tags:
- Templates
summary: Convert docker-compose YAML to a template graph
description: |
Parses a docker-compose YAML document and returns a v2 template
config (`version: 2`, `services[]`). Well-known database images
(postgres, redis, mongo, mysql, mariadb, clickhouse, dragonfly)
become managed-database members; other images become web services.
`build:` contexts are flagged in `warnings` — Containr deploys
images or git repos, not local build contexts. The returned config
can be saved via POST /templates or deployed directly via
POST /templates/deploy.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- compose_yaml
properties:
compose_yaml:
type: string
description: Raw docker-compose YAML (max 512 KiB)
responses:
'200':
description: Converted config
content:
application/json:
schema:
type: object
properties:
config:
$ref: '#/components/schemas/TemplateConfig'
variables:
type: array
items:
type: object
warnings:
type: array
items:
type: string
/templates/deploy:
post:
tags:
- Templates
summary: Deploy an ad-hoc service graph
description: |
Deploys a v2 graph config (config.services[]) without a stored
template — the companion to POST /templates/import/compose.
Members are created in dependency order; `database` members become
managed databases attached to the project network under their key
as DNS alias, and deployments are enqueued for service members.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- project_id
- config
properties:
project_id:
type: string
config:
$ref: '#/components/schemas/TemplateConfig'
variables:
type: object
additionalProperties:
type: string
plan:
type: string
region:
type: string
responses:
'201':
description: Graph deployed
content:
application/json:
schema:
type: object
properties:
resource:
type: string
created:
type: array
items:
type: object
properties:
key:
type: string
kind:
type: string
id:
type: string
name:
type: string
deployment_id:
type: string
/projects/{id}/import-compose:
post:
tags:
- Projects
summary: Deploy a docker-compose file into a project
description: |
Parses a docker-compose YAML document and deploys it directly into
the project — no template row. Well-known database images
(postgres, mysql, redis, mongo, mariadb, clickhouse, dragonfly)
become managed databases attached to the project network under
their service name as DNS alias; other services are created and
deployed in dependency order. Returns the created resources plus
any import warnings (unsupported keys, missing values).
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- compose_yaml
properties:
compose_yaml:
type: string
description: Full docker-compose YAML document (max 512 KiB)
variables:
type: object
additionalProperties:
type: string
plan:
type: string
region:
type: string
responses:
'201':
description: Stack deployed
content:
application/json:
schema:
type: object
properties:
resource:
type: string
created:
type: array
items:
type: object
warnings:
type: array
items:
type: string
'400':
description: Invalid compose YAML or unresolved references
'403':
description: Access denied
'404':
description: Project not found
# Agent Onboarding Tokens
/agent-tokens:
post:
tags:
- Agents
summary: Issue agent onboarding token
description: Generates a new agent onboarding token. The raw token is returned once and never stored — only its SHA-256 hash persists.
security:
- bearerAuth: []
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAgentTokenRequest'
responses:
'201':
description: Token issued; raw value returned once
content:
application/json:
schema:
$ref: '#/components/schemas/AgentAuthTokenCreated'
get:
tags:
- Agents
summary: List agent onboarding tokens
description: Returns issued onboarding token metadata (never token values or hashes).
security:
- bearerAuth: []
responses:
'200':
description: Token list
content:
application/json:
schema:
type: object
properties:
tokens:
type: array
items:
$ref: '#/components/schemas/AgentAuthToken'
/agent-tokens/{id}:
delete:
tags:
- Agents
summary: Revoke agent onboarding token
description: Marks a token as revoked. Agents presenting it are rejected from then on.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Token revoked
content:
application/json:
schema:
type: object
properties:
status:
type: string
id:
type: string
'404':
description: Token not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Notifications
/notifications:
get:
tags:
- Notifications
summary: List notifications for the current user
security:
- bearerAuth: []
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: Notifications and unread count
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationListResponse'
/notifications/{id}/read:
post:
tags:
- Notifications
summary: Mark a notification as read
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Marked read
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/notifications/read-all:
post:
tags:
- Notifications
summary: Mark all notifications as read
security:
- bearerAuth: []
responses:
'200':
description: All marked read
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
# Outbound Webhooks
/webhooks:
get:
tags:
- Webhooks
summary: List outbound webhooks
security:
- bearerAuth: []
responses:
'200':
description: Webhooks for the caller (secrets masked)
content:
application/json:
schema:
type: object
properties:
webhooks:
type: array
items:
$ref: '#/components/schemas/OutboundWebhook'
post:
tags:
- Webhooks
summary: Create an outbound webhook
description: |
Receives signed POST deliveries for every audited action matching
the event list — "resource.action" names, "resource.*" wildcards,
or "*" for everything. The secret is returned once; deliveries
carry X-Containr-Signature: sha256=<hmac> over the raw body.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
- url
- events
properties:
name:
type: string
url:
type: string
secret:
type: string
description: Signing secret (auto-generated when omitted)
events:
type: array
items:
type: string
example: ["service.*", "deployment.fail"]
headers:
type: object
additionalProperties:
type: string
enabled:
type: boolean
default: true
responses:
'201':
description: Webhook created (secret revealed once)
content:
application/json:
schema:
$ref: '#/components/schemas/OutboundWebhook'
'400':
description: Invalid name, URL, or empty event list
/webhooks/{id}:
patch:
tags:
- Webhooks
summary: Update a webhook
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
url:
type: string
secret:
type: string
events:
type: array
items:
type: string
headers:
type: object
additionalProperties:
type: string
enabled:
type: boolean
responses:
'200':
description: Updated webhook
content:
application/json:
schema:
$ref: '#/components/schemas/OutboundWebhook'
'404':
description: Webhook not found
delete:
tags:
- Webhooks
summary: Delete a webhook
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/webhooks/{id}/deliveries:
get:
tags:
- Webhooks
summary: List delivery attempts for a webhook
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Recent deliveries (newest first, max 100)
content:
application/json:
schema:
type: object
properties:
deliveries:
type: array
items:
$ref: '#/components/schemas/WebhookDelivery'
/webhooks/{id}/test:
post:
tags:
- Webhooks
summary: Queue a test ping delivery
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'202':
description: Delivery queued
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/operations:
get:
tags:
- Operations
summary: Cross-cutting operations view
description: |
Single snapshot of platform work scoped to the caller's projects
(admins see all): active deployments, in-memory deploy-queue
depth per service, deployments that failed in the last 24h,
cron executions and database backups from the last 24h.
security:
- bearerAuth: []
responses:
'200':
description: Operations snapshot
content:
application/json:
schema:
type: object
properties:
active_deployments:
type: array
items:
type: object
deploy_queue:
type: array
items:
type: object
properties:
service_id:
type: string
running:
type: boolean
queued:
type: integer
recent_failures:
type: array
items:
type: object
cron_runs:
type: array
items:
type: object
backups:
type: array
items:
type: object
/activity:
get:
tags:
- Operations
summary: Activity feed
description: >-
Enriched audit events (severity, category, label) scoped to the
caller's visible projects; admins see everything.
security:
- bearerAuth: []
parameters:
- {name: severity, in: query, schema: {type: string, enum: [info, success, warning, error]}}
- {name: category, in: query, schema: {type: string}}
- {name: resource, in: query, schema: {type: string}}
- {name: project_id, in: query, schema: {type: string, format: uuid}}
- {name: since, in: query, schema: {type: string, format: date-time}}
- {name: page, in: query, schema: {type: integer, default: 1}}
- {name: limit, in: query, schema: {type: integer, default: 50, maximum: 200}}
responses:
'200':
description: Feed entries
content:
application/json:
schema:
type: object
properties:
activity:
type: array
items:
$ref: '#/components/schemas/AuditLog'
page: {type: integer}
limit: {type: integer}
has_more: {type: boolean}
/projects/{id}/activity:
get:
tags:
- Operations
summary: Per-project activity timeline
description: Audit events correlated to this project's services, deployments, databases and the project record itself.
security:
- bearerAuth: []
parameters:
- {name: id, in: path, required: true, schema: {type: string}}
- {name: page, in: query, schema: {type: integer, default: 1}}
- {name: limit, in: query, schema: {type: integer, default: 50, maximum: 200}}
responses:
'200':
description: Feed entries
content:
application/json:
schema:
type: object
properties:
activity:
type: array
items:
$ref: '#/components/schemas/AuditLog'
'404':
description: Project not found or not visible
/banners/active:
get:
tags:
- Banners
summary: Active announcement banners
description: Banners currently active (enabled and within their optional schedule window).
security:
- bearerAuth: []
responses:
'200':
description: Active banners
content:
application/json:
schema:
type: object
properties:
banners:
type: array
items:
type: object
properties:
id: {type: string}
title: {type: string}
body: {type: string}
level: {type: string, enum: [info, success, warning, error]}
active: {type: boolean}
dismissible: {type: boolean}
starts_at: {type: string, format: date-time, nullable: true}
ends_at: {type: string, format: date-time, nullable: true}
created_at: {type: string, format: date-time}
/admin/banners:
get:
tags:
- Banners
summary: List all banners (admin)
security:
- bearerAuth: []
responses:
'200':
description: All banners
content:
application/json:
schema:
type: object
properties:
banners:
type: array
items:
type: object
post:
tags:
- Banners
summary: Create a banner (admin)
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title]
properties:
title: {type: string}
body: {type: string}
level: {type: string, enum: [info, success, warning, error], default: info}
active: {type: boolean, default: true}
dismissible: {type: boolean, default: true}
starts_at: {type: string, format: date-time}
ends_at: {type: string, format: date-time}
responses:
'201':
description: Created banner
content:
application/json:
schema:
type: object
/admin/banners/{id}:
patch:
tags:
- Banners
summary: Update a banner (admin)
security:
- bearerAuth: []
parameters:
- {name: id, in: path, required: true, schema: {type: string}}
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title: {type: string}
body: {type: string}
level: {type: string, enum: [info, success, warning, error]}
active: {type: boolean}
dismissible: {type: boolean}
starts_at: {type: string, format: date-time}
ends_at: {type: string, format: date-time}
responses:
'200':
description: Updated banner
content:
application/json:
schema:
type: object
delete:
tags:
- Banners
summary: Delete a banner (admin)
security:
- bearerAuth: []
parameters:
- {name: id, in: path, required: true, schema: {type: string}}
responses:
'204':
description: Deleted
/auth/invites/{token}:
get:
tags:
- Invites
summary: Validate an invite token (public)
responses:
'200':
description: Invite state
content:
application/json:
schema:
type: object
properties:
valid: {type: boolean}
used: {type: boolean}
expired: {type: boolean}
email: {type: string, nullable: true}
expires_at: {type: string, format: date-time}
'404':
description: Invite not found
/auth/accept-invite:
post:
tags:
- Invites
summary: Register via an invite link (public)
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [token, name, email, password]
properties:
token: {type: string}
name: {type: string}
email: {type: string}
password: {type: string, minLength: 8}
responses:
'201':
description: Created session
content:
application/json:
schema:
$ref: '#/components/schemas/LoginResponse'
'410':
description: Invite used or expired
/admin/invites:
get:
tags:
- Invites
summary: List invites (admin)
security:
- bearerAuth: []
responses:
'200':
description: All invites
content:
application/json:
schema:
type: object
properties:
invites:
type: array
items:
type: object
post:
tags:
- Invites
summary: Create an invite link (admin)
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
type: object
properties:
email: {type: string, description: Optionally bind the invite to this email}
expires_in_hours: {type: integer, default: 168, minimum: 1, maximum: 2160}
responses:
'201':
description: Created invite with one-time token
content:
application/json:
schema:
type: object
properties:
invite: {type: object}
token: {type: string, description: Shown once}
url: {type: string}
/admin/invites/{id}:
delete:
tags:
- Invites
summary: Revoke an invite (admin)
security:
- bearerAuth: []
parameters:
- {name: id, in: path, required: true, schema: {type: string}}
responses:
'204':
description: Revoked
/branding:
get:
tags:
- Branding
summary: White-label branding (public)
description: |
Instance branding payload — product name, logo/favicon URLs,
accent color, docs/support links. Unauthenticated so the login
page and shell can brand themselves before a session exists.
Unset fields return Containr defaults.
responses:
'200':
description: Branding configuration
content:
application/json:
schema:
$ref: '#/components/schemas/Branding'
# Audit Logs
/audit-logs:
get:
tags:
- Audit
summary: List audit logs
description: Retrieve audit log entries with optional filters
security:
- bearerAuth: []
parameters:
- name: resource
in: query
required: false
description: Filter audit logs by resource type
schema:
type: string
- name: actor
in: query
required: false
description: Filter audit logs by actor email substring
schema:
type: string
- name: user_id
in: query
required: false
description: Filter audit logs by actor user UUID
schema:
type: string
format: uuid
- name: since
in: query
required: false
description: Only return entries created at or after this RFC3339 timestamp
schema:
type: string
format: date-time
- name: action
in: query
required: false
description: Filter audit logs by action type
schema:
type: string
- name: page
in: query
required: false
description: 1-based page number
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
required: false
description: Number of entries per page
schema:
type: integer
minimum: 1
maximum: 100
default: 50
responses:
'200':
description: Audit logs retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/AuditLogListResponse'
/audit-logs/{resource}/{id}:
get:
tags:
- Audit
summary: List resource audit logs
description: Retrieve audit log entries for a specific resource and resource ID
security:
- bearerAuth: []
parameters:
- name: resource
in: path
required: true
description: Resource type
schema:
type: string
- name: id
in: path
required: true
description: Resource ID
schema:
type: string
responses:
'200':
description: Resource audit logs retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/AuditLogListResponse'
# Databases
/databases:
get:
tags:
- Databases
summary: List databases
description: Retrieve all managed databases for the authenticated user
security:
- bearerAuth: []
responses:
'200':
description: Databases retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseListResponse'
post:
tags:
- Databases
summary: Create database
description: Create a new managed database and start provisioning
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDatabaseRequest'
responses:
'201':
description: Database provisioning started
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseCreateResponse'
/databases/register-external:
post:
tags:
- Databases
summary: Register external database
description: Record a database hosted elsewhere — connection is probed first (postgres/redis get protocol-level checks, others TCP). Password stored encrypted, never returned.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ExternalDatabaseRequest'
- type: object
required: [name]
responses:
'201':
description: External database registered
'400':
description: Validation failed or connection probe failed
'409':
description: Name already in use
/databases/test-connection:
post:
tags:
- Databases
summary: Probe a database connection
description: Ad-hoc connectivity check — postgres via libpq ping, redis/dragonfly via PING, other engines via TCP dial. Always 200; `ok` carries the result.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ExternalDatabaseRequest'
responses:
'200':
description: Probe result
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
latency_ms:
type: integer
error:
type: string
/databases/{id}/test-connection:
post:
tags:
- Databases
summary: Re-probe a registered external database
description: Uses the stored credentials. External databases only.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Probe result (`ok` carries the outcome)
'404':
description: Database not found
/databases/{id}:
get:
tags:
- Databases
summary: Get database
description: Retrieve a specific database
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
responses:
'200':
description: Database retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Database'
put:
tags:
- Databases
summary: Update database
description: Update mutable database metadata (name or plan)
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateDatabaseRequest'
responses:
'200':
description: Database updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
delete:
tags:
- Databases
summary: Delete database
description: Delete managed database and associated runtime
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
responses:
'200':
description: Database deleted successfully
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/databases/{id}/action:
post:
tags:
- Databases
summary: Execute database action
description: Execute start, stop, or restart action for a managed database
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseActionRequest'
responses:
'200':
description: Action accepted
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseActionResponse'
/databases/{id}/backup:
post:
tags:
- Databases
summary: Create backup
description: Create a managed snapshot backup for a database
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
responses:
'201':
description: Backup started
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseBackupCreateResponse'
/databases/{id}/restore:
post:
tags:
- Databases
summary: Restore backup
description: Restore a managed database from a completed backup
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DatabaseRestoreRequest'
responses:
'200':
description: Restore started
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/databases/{id}/backups/import:
post:
tags:
- Databases
summary: Import a backup archive
description: >-
Upload a `.tar.gz` archive (multipart field `file` or a raw
application/gzip body) to create a new restore point. The archive
lands in the backup volume and, when a backup target is assigned,
is also shipped offsite. Managed databases only; 2 GiB ceiling.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: Database ID
schema:
type: string
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
application/gzip:
schema:
type: string
format: binary
responses:
'201':
description: Backup imported
content:
application/json:
schema:
type: object
properties:
backup_id:
type: string
size:
type: string
status:
type: string
'400':
description: Invalid archive
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: Archive too large
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/databases/{id}/backups/{bid}/download:
get:
tags:
- Databases
summary: Download a completed backup archive
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: bid
in: path
required: true
schema:
type: string
security:
- bearerAuth: []
responses:
'200':
description: Backup archive stream
content:
application/gzip:
schema:
type: string
format: binary
'404':
description: Backup not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Backup not completed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Git Integration
/git/providers:
get:
tags:
- Git
summary: List Git providers
description: Retrieve available Git providers
security:
- bearerAuth: []
responses:
'200':
description: Git providers retrieved successfully
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/GitProvider'
post:
tags:
- Git
summary: Add Git provider
description: Add a new Git provider
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateGitProviderRequest'
responses:
'201':
description: Git provider added successfully
content:
application/json:
schema:
$ref: '#/components/schemas/GitProvider'
/git/providers/{providerId}/repositories:
get:
tags:
- Git
summary: List repositories
description: Retrieve repositories from a Git provider
security:
- bearerAuth: []
parameters:
- name: providerId
in: path
required: true
description: Git provider ID
schema:
type: string
responses:
'200':
description: Repositories retrieved successfully
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/GitRepository'
# Top-level probes (served outside /api/v1)
/live:
servers:
- url: http://localhost:8080
get:
tags:
- Health
summary: Liveness probe
description: Process liveness check served at the root, outside /api/v1.
responses:
'200':
description: Process is alive
/ready:
servers:
- url: http://localhost:8080
get:
tags:
- Health
summary: Readiness probe
description: Same handler as /health — reports database and Redis status.
responses:
'200':
description: Service is ready
content:
application/json:
schema:
$ref: '#/components/schemas/HealthResponse'
# Authentication
/auth/bootstrap:
get:
tags:
- Authentication
summary: Bootstrap status
description: Reports whether the instance already has a registered user, which auth providers are configured, and whether public registration is open. Drives the first-run setup gate.
responses:
'200':
description: Bootstrap state
content:
application/json:
schema:
type: object
properties:
has_users:
type: boolean
description: True when at least one account exists
user_count:
type: integer
mode:
type: string
enum: [register, login]
description: register when the instance has no users, login otherwise
providers:
type: array
items:
type: string
description: OAuth providers with real credentials configured (e.g. github, google). Empty on self-hosted installs.
signup_enabled:
type: boolean
description: True when the owner re-opened public registration in Settings
/settings:
get:
tags:
- Settings
summary: Read platform settings
description: Admin only. Returns in-app settings that override environment variables.
security:
- bearerAuth: []
responses:
'200':
description: Current platform settings
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformSettings'
'403':
description: Admin access required
put:
tags:
- Settings
summary: Update platform settings
description: Admin only. Provided keys are applied immediately; the Cloudflare tunnel token starts/stops the managed cloudflared sidecar.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
signup_enabled:
type: boolean
description: Allow new public account registration after bootstrap
cloudflare_tunnel_token:
type: string
description: Cloudflare Tunnel token. Empty string clears the stored token and removes the cloudflared container.
branding:
type: object
description: White-label fields. Empty string clears a field back to the Containr default.
properties:
product_name: {type: string}
logo_url: {type: string}
favicon_url: {type: string}
accent_color: {type: string}
docs_url: {type: string}
support_url: {type: string}
responses:
'200':
description: Updated platform settings
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformSettings'
'403':
description: Admin access required
# User Management
/users:
post:
tags:
- User
summary: Create user (manual)
description: Manually create a user account. Used for internal/admin user creation outside the bootstrap flow.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ManualUserCreateRequest'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Services
/services/{id}/metrics:
get:
tags:
- Services
summary: Service metrics
description: Live resource usage for the service's containers (CPU, memory, network, block I/O via Docker stats).
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Current service metrics
content:
application/json:
schema:
type: object
properties:
metrics:
$ref: '#/components/schemas/ServiceMetrics'
'404':
description: Service not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/services/{id}/variables:
get:
tags:
- Services
summary: List service variables
description: Environment variables for a service. Secret values are masked.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Variables retrieved
content:
application/json:
schema:
type: object
properties:
variables:
type: array
items:
$ref: '#/components/schemas/ServiceVariable'
'404':
description: Service not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Services
summary: Replace service variables
description: Replace the full variable set for a service.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateVariablesRequest'
responses:
'200':
description: Variables updated
content:
application/json:
schema:
type: object
properties:
variables:
type: array
items:
$ref: '#/components/schemas/ServiceVariable'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects/{id}/variables:
get:
tags:
- Projects
summary: List shared project variables
description: Project-level variables shared across services. Services reference them as `${{shared.KEY}}` in environment values — resolved at deploy/reconcile, not live-updated. Secret values are masked.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Variables retrieved
content:
application/json:
schema:
type: object
properties:
variables:
type: array
items:
$ref: '#/components/schemas/ServiceVariable'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Projects
summary: Replace shared project variables
description: Replace the full shared-variable set for a project. Fetch the current list first and merge — the server replaces wholesale. Masked secret placeholders (`********`) keep the stored value.
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateVariablesRequest'
responses:
'200':
description: Variables updated
content:
application/json:
schema:
type: object
properties:
variables:
type: array
items:
$ref: '#/components/schemas/ServiceVariable'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Git integration
/git/github-app/install-url:
get:
tags:
- Git
summary: GitHub App install URL
description: Returns the URL to install the Containr GitHub App, or 404 when no app is configured.
security:
- bearerAuth: []
responses:
'200':
description: Install URL
content:
application/json:
schema:
type: object
properties:
install_url:
type: string
format: uri
'404':
description: GitHub App not configured
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/git/github-app/connect:
post:
tags:
- Git
summary: Connect GitHub App installation
description: Register a completed GitHub App installation as a git provider.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectGitHubAppRequest'
responses:
'201':
description: Provider created
content:
application/json:
schema:
$ref: '#/components/schemas/GitProvider'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/admin/git/github-app:
get:
tags:
- Admin
summary: GitHub App provisioning status
description: Shows whether the instance GitHub App is configured, and whether credentials come from app_settings or environment variables.
security:
- bearerAuth: []
responses:
'200':
description: Provisioning status
content:
application/json:
schema:
type: object
properties:
configured: {type: boolean}
source: {type: string, enum: [settings, env, none]}
app_id: {type: string}
slug: {type: string}
name: {type: string}
/admin/git/github-app/manifest:
post:
tags:
- Admin
summary: Build GitHub App manifest
description: >-
Returns a GitHub App manifest for self-provisioning. The client POSTs
`manifest` verbatim as a form field to `url`; GitHub then redirects to
the instance's /git/github-app/callback with a code.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [base_url]
properties:
base_url: {type: string, description: Public https base URL of this instance}
name: {type: string}
organization: {type: string, description: Create the app under this GitHub organization}
responses:
'200':
description: Manifest + submission URL
content:
application/json:
schema:
type: object
properties:
url: {type: string}
manifest: {type: string, description: JSON string — POST as form field `manifest`}
state: {type: string}
/admin/git/github-app/convert:
post:
tags:
- Admin
summary: Exchange manifest callback code
description: Exchanges the `code` from the manifest redirect for the app credentials and stores them in app_settings (overriding env vars).
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [code]
properties:
code: {type: string}
responses:
'200':
description: App provisioned
content:
application/json:
schema:
type: object
properties:
app_id: {type: integer}
slug: {type: string}
name: {type: string}
'502':
description: GitHub conversion failed
/git/providers/{providerId}:
delete:
tags:
- Git
summary: Delete git provider
description: Remove a git provider and its stored credentials.
security:
- bearerAuth: []
parameters:
- name: providerId
in: path
required: true
schema:
type: string
responses:
'200':
description: Provider deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
'404':
description: Provider not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/git/providers/{providerId}/repositories/{owner}/{repo}/branches:
get:
tags:
- Git
summary: List repository branches
description: List branches for a repository through the provider API.
security:
- bearerAuth: []
parameters:
- name: providerId
in: path
required: true
schema:
type: string
- name: owner
in: path
required: true
schema:
type: string
- name: repo
in: path
required: true
schema:
type: string
responses:
'200':
description: Branches retrieved
content:
application/json:
schema:
type: object
properties:
branches:
type: array
items:
$ref: '#/components/schemas/GitBranch'
'502':
description: Provider API error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/git/repositories/connect:
post:
tags:
- Git
summary: Connect repository
description: Connect a provider repository so it can back services and webhooks.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectGitRepoRequest'
responses:
'201':
description: Repository connected
content:
application/json:
schema:
$ref: '#/components/schemas/GitRepository'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/git/repositories:
get:
tags:
- Git
summary: List connected repositories
description: Repositories connected to Containr across all providers.
security:
- bearerAuth: []
responses:
'200':
description: Connected repositories
content:
application/json:
schema:
type: object
properties:
repositories:
type: array
items:
$ref: '#/components/schemas/GitRepository'
/git/webhooks:
post:
tags:
- Git
summary: Create webhook
description: Register a webhook on a connected repository to trigger deployments on push.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWebhookRequest'
responses:
'201':
description: Webhook created
content:
application/json:
schema:
$ref: '#/components/schemas/GitWebhook'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Builds
/builds/plan:
post:
tags:
- Builds
summary: Preview build plan
description: Resolve how a build would run (detected build type, commands) without executing it.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BuildRequest'
responses:
'200':
description: Resolved build plan
content:
application/json:
schema:
type: object
properties:
plan:
type: object
description: Detected build type, commands, and resolved options
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/builds/detect:
get:
tags:
- Builds
summary: Detect build type
description: Auto-detect the build strategy (Dockerfile, Railpack, etc.) for a source path.
security:
- bearerAuth: []
parameters:
- name: source_path
in: query
schema:
type: string
responses:
'200':
description: Detected build type
content:
application/json:
schema:
type: object
properties:
build_type:
type: string
detected:
type: boolean
# System
/system/upgrade/status:
get:
tags:
- System
summary: Upgrade status
description: Current version, latest available image, and whether an upgrade is in progress.
security:
- bearerAuth: []
responses:
'200':
description: Upgrade status
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeStatus'
/system/upgrade/pull:
post:
tags:
- System
summary: Pull upgrade image
description: Pull the latest Containr image and restart the stack to self-upgrade.
security:
- bearerAuth: []
responses:
'200':
description: Upgrade started
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/system/host:
get:
tags:
- System
summary: Host monitoring
description: 'Host-level telemetry: CPU, memory, disk, network, uptime, and container counts.'
security:
- bearerAuth: []
responses:
'200':
description: Host metrics
content:
application/json:
schema:
$ref: '#/components/schemas/HostMonitoring'
# WebSocket
/ws:
get:
tags:
- Realtime
summary: WebSocket stream
description: Upgrades to WebSocket. Streams build status, deployment events, and container log output.
security:
- bearerAuth: []
responses:
'101':
description: WebSocket upgrade
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Autoscaling
/scaling/policies:
get:
tags:
- Scaling
summary: List scaling policies
security:
- bearerAuth: []
responses:
'200':
description: All scaling policies
content:
application/json:
schema:
type: object
properties:
policies:
type: array
items:
$ref: '#/components/schemas/ScalingPolicy'
count:
type: integer
post:
tags:
- Scaling
summary: Create or replace scaling policy
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScalingPolicy'
responses:
'201':
description: Policy stored
content:
application/json:
schema:
type: object
properties:
message:
type: string
policy:
$ref: '#/components/schemas/ScalingPolicy'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/scaling/policies/{serviceId}:
get:
tags:
- Scaling
summary: Get scaling policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Scaling policy
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/ScalingPolicy'
'404':
description: Policy not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Scaling
summary: Update scaling policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScalingPolicy'
responses:
'200':
description: Policy updated
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/ScalingPolicy'
delete:
tags:
- Scaling
summary: Delete scaling policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Policy deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/scaling/services:
get:
tags:
- Scaling
summary: List service scaling states
security:
- bearerAuth: []
responses:
'200':
description: Per-service scaling state (replicas, last scale, cooldowns)
content:
application/json:
schema:
type: object
properties:
services:
type: array
items:
type: object
/scaling/services/{serviceId}:
get:
tags:
- Scaling
summary: Get service scaling state
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Scaling state for one service
content:
application/json:
schema:
type: object
/scaling/services/{serviceId}/history:
get:
tags:
- Scaling
summary: Scaling history
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Scaling events for the service
content:
application/json:
schema:
type: object
properties:
history:
type: array
items:
$ref: '#/components/schemas/ScalingEvent'
/scaling/services/{serviceId}/scale:
post:
tags:
- Scaling
summary: Manual scale
description: Immediately scale a service to a replica count.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- replicas
properties:
replicas:
type: integer
minimum: 1
maximum: 20
reason:
type: string
responses:
'200':
description: Scale event recorded
content:
application/json:
schema:
$ref: '#/components/schemas/ScalingEvent'
'400':
description: Invalid replica count or cooldown active
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/scaling/status:
get:
tags:
- Scaling
summary: Autoscaler status
security:
- bearerAuth: []
responses:
'200':
description: Whether the autoscaler is enabled plus counts
content:
application/json:
schema:
type: object
/scaling/enable:
post:
tags:
- Scaling
summary: Enable autoscaler
security:
- bearerAuth: []
responses:
'200':
description: Autoscaler enabled
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/scaling/disable:
post:
tags:
- Scaling
summary: Disable autoscaler
security:
- bearerAuth: []
responses:
'200':
description: Autoscaler disabled
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/scaling/metrics:
get:
tags:
- Scaling
summary: Scaling engine metrics
security:
- bearerAuth: []
responses:
'200':
description: Internal autoscaler metrics
content:
application/json:
schema:
type: object
/scaling/events:
get:
tags:
- Scaling
summary: Recent scaling events
security:
- bearerAuth: []
responses:
'200':
description: All recent scale up/down events
content:
application/json:
schema:
type: object
properties:
events:
type: array
items:
$ref: '#/components/schemas/ScalingEvent'
# High availability
/ha/status:
get:
tags:
- HA
summary: HA status
security:
- bearerAuth: []
responses:
'200':
description: Overall HA status (enabled, policies, active alerts)
content:
application/json:
schema:
type: object
/ha/enable:
post:
tags:
- HA
summary: Enable HA management
security:
- bearerAuth: []
responses:
'200':
description: HA enabled
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/disable:
post:
tags:
- HA
summary: Disable HA management
security:
- bearerAuth: []
responses:
'200':
description: HA disabled
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/failover:
post:
tags:
- HA
summary: Trigger failover
description: Manually trigger a failover evaluation across services with failover policies.
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
responses:
'200':
description: Failover triggered
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/failover/policies:
get:
tags:
- HA
summary: List failover policies
security:
- bearerAuth: []
responses:
'200':
description: All failover policies
content:
application/json:
schema:
type: object
properties:
policies:
type: array
items:
$ref: '#/components/schemas/FailoverPolicy'
post:
tags:
- HA
summary: Create or replace failover policy
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FailoverPolicy'
responses:
'201':
description: Policy stored
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/FailoverPolicy'
/ha/failover/policies/{serviceId}:
get:
tags:
- HA
summary: Get failover policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Failover policy
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/FailoverPolicy'
'404':
description: Policy not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- HA
summary: Update failover policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FailoverPolicy'
responses:
'200':
description: Policy updated
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/FailoverPolicy'
delete:
tags:
- HA
summary: Delete failover policy
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ServiceIdParam'
responses:
'200':
description: Policy deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/health/checks:
get:
tags:
- HA
summary: List health checks
security:
- bearerAuth: []
responses:
'200':
description: Configured health checks
content:
application/json:
schema:
type: object
properties:
checks:
type: array
items:
$ref: '#/components/schemas/HealthCheck'
post:
tags:
- HA
summary: Add health check
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/HealthCheck'
responses:
'201':
description: Health check created
content:
application/json:
schema:
type: object
properties:
check:
$ref: '#/components/schemas/HealthCheck'
/ha/health/checks/{checkId}:
get:
tags:
- HA
summary: Get health check
security:
- bearerAuth: []
parameters:
- name: checkId
in: path
required: true
schema:
type: string
responses:
'200':
description: Health check
content:
application/json:
schema:
type: object
properties:
check:
$ref: '#/components/schemas/HealthCheck'
'404':
description: Check not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- HA
summary: Update health check
security:
- bearerAuth: []
parameters:
- name: checkId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/HealthCheck'
responses:
'200':
description: Health check updated
content:
application/json:
schema:
type: object
properties:
check:
$ref: '#/components/schemas/HealthCheck'
delete:
tags:
- HA
summary: Delete health check
security:
- bearerAuth: []
parameters:
- name: checkId
in: path
required: true
schema:
type: string
responses:
'200':
description: Health check deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/health/results:
get:
tags:
- HA
summary: Health check results
security:
- bearerAuth: []
responses:
'200':
description: Latest result per health check
content:
application/json:
schema:
type: object
/ha/alerts/rules:
get:
tags:
- HA
summary: List alert rules
security:
- bearerAuth: []
responses:
'200':
description: All alert rules
content:
application/json:
schema:
type: object
properties:
rules:
type: array
items:
$ref: '#/components/schemas/AlertRule'
post:
tags:
- HA
summary: Add alert rule
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AlertRule'
responses:
'201':
description: Alert rule created
content:
application/json:
schema:
type: object
properties:
rule:
$ref: '#/components/schemas/AlertRule'
/ha/alerts/rules/{ruleId}:
get:
tags:
- HA
summary: Get alert rule
security:
- bearerAuth: []
parameters:
- name: ruleId
in: path
required: true
schema:
type: string
responses:
'200':
description: Alert rule
content:
application/json:
schema:
type: object
properties:
rule:
$ref: '#/components/schemas/AlertRule'
'404':
description: Rule not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- HA
summary: Update alert rule
security:
- bearerAuth: []
parameters:
- name: ruleId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AlertRule'
responses:
'200':
description: Alert rule updated
content:
application/json:
schema:
type: object
properties:
rule:
$ref: '#/components/schemas/AlertRule'
delete:
tags:
- HA
summary: Delete alert rule
security:
- bearerAuth: []
parameters:
- name: ruleId
in: path
required: true
schema:
type: string
responses:
'200':
description: Alert rule deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/alerts/active:
get:
tags:
- HA
summary: Active alerts
security:
- bearerAuth: []
responses:
'200':
description: Currently firing alerts
content:
application/json:
schema:
type: object
properties:
alerts:
type: array
items:
type: object
/ha/alerts/{alertId}/resolve:
post:
tags:
- HA
summary: Resolve alert
security:
- bearerAuth: []
parameters:
- name: alertId
in: path
required: true
schema:
type: string
responses:
'200':
description: Alert resolved
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/ha/notifiers:
get:
tags:
- HA
summary: List notifiers
security:
- bearerAuth: []
responses:
'200':
description: Configured alert notifiers
content:
application/json:
schema:
type: object
properties:
notifiers:
type: array
items:
$ref: '#/components/schemas/Notifier'
post:
tags:
- HA
summary: Add notifier
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NotifierRequest'
responses:
'201':
description: Notifier created
content:
application/json:
schema:
type: object
properties:
notifier:
$ref: '#/components/schemas/Notifier'
/ha/notifiers/{notifierId}:
get:
tags:
- HA
summary: Get notifier
security:
- bearerAuth: []
parameters:
- name: notifierId
in: path
required: true
schema:
type: string
responses:
'200':
description: Notifier
content:
application/json:
schema:
type: object
properties:
notifier:
$ref: '#/components/schemas/Notifier'
'404':
description: Notifier not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- HA
summary: Delete notifier
security:
- bearerAuth: []
parameters:
- name: notifierId
in: path
required: true
schema:
type: string
responses:
'200':
description: Notifier deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
# Node agents — management (JWT-authenticated)
/nodes/options:
get:
tags:
- Agents
summary: Node options for service placement
description: Minimal id/name/status list of registered node agents — available to any authenticated user for the service placement picker. Full agent data is admin-only under /agents.
security:
- bearerAuth: []
responses:
'200':
description: Node options
content:
application/json:
schema:
type: object
properties:
nodes:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
status:
type: string
/agents:
get:
tags:
- Agents
summary: List node agents
security:
- bearerAuth: []
responses:
'200':
description: All registered node agents
content:
application/json:
schema:
type: object
properties:
agents:
type: array
items:
$ref: '#/components/schemas/NodeAgent'
/agents/{id}:
get:
tags:
- Agents
summary: Get node agent
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Agent detail
content:
application/json:
schema:
type: object
properties:
agent:
$ref: '#/components/schemas/NodeAgent'
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Agents
summary: Update node agent
description: Partial update — accepts any subset of agent fields (name, status, labels, etc.).
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
requestBody:
required: true
content:
application/json:
schema:
type: object
description: Subset of NodeAgent fields to update
responses:
'200':
description: Agent updated
content:
application/json:
schema:
type: object
properties:
agent:
$ref: '#/components/schemas/NodeAgent'
delete:
tags:
- Agents
summary: Deregister node agent
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Agent removed
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/agents/{id}/containers:
get:
tags:
- Agents
summary: List agent containers
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Containers running on the agent
content:
application/json:
schema:
type: object
properties:
containers:
type: array
items:
$ref: '#/components/schemas/ContainerInstance'
post:
tags:
- Agents
summary: Create container on agent
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateContainerRequest'
responses:
'201':
description: Container created
content:
application/json:
schema:
type: object
properties:
container:
$ref: '#/components/schemas/ContainerInstance'
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/containers/{containerId}/start:
post:
tags:
- Agents
summary: Start container
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
- $ref: '#/components/parameters/ContainerIdParam'
responses:
'200':
description: Container start dispatched
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/agents/{id}/containers/{containerId}/stop:
post:
tags:
- Agents
summary: Stop container
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
- $ref: '#/components/parameters/ContainerIdParam'
responses:
'200':
description: Container stop dispatched
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/agents/{id}/containers/{containerId}/restart:
post:
tags:
- Agents
summary: Restart container
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
- $ref: '#/components/parameters/ContainerIdParam'
responses:
'200':
description: Container restart dispatched
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/agents/{id}/containers/{containerId}:
delete:
tags:
- Agents
summary: Remove container
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
- $ref: '#/components/parameters/ContainerIdParam'
responses:
'200':
description: Container removal dispatched
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/api/agents/install.sh:
servers:
- url: http://localhost:8080
get:
tags:
- Agents
summary: Agent install script
description: Public bootstrap script — `curl | bash -s -- --url <api> --token <enroll-token>`.
security: []
responses:
'200':
description: Bourne shell installer
content:
text/x-sh:
schema:
type: string
/api/agents/download/{platform}:
servers:
- url: http://localhost:8080
get:
tags:
- Agents
summary: Download a bundled agent binary
description: "platform: linux-amd64 | linux-arm64. Bundled in release images; 404 when absent (install script falls back to GH releases)."
security: []
parameters:
- name: platform
in: path
required: true
schema:
type: string
enum: [linux-amd64, linux-arm64]
responses:
'200':
description: Agent binary
content:
application/octet-stream:
schema:
type: string
format: binary
'404':
description: No bundled binary for platform
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/prune:
post:
tags:
- Agents
summary: Enqueue a bounded docker prune on a node
description: Queues a `prune` command — `docker system prune -af`, volumes excluded unless requested.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
requestBody:
content:
application/json:
schema:
type: object
properties:
until:
type: string
description: Only prune objects older than this duration (e.g. "168h").
volumes:
type: boolean
description: Also prune volumes — destructive, off by default.
responses:
'202':
description: Prune command queued
content:
application/json:
schema:
type: object
properties:
command:
$ref: '#/components/schemas/AgentCommand'
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/cordon:
post:
tags:
- Agents
summary: Cordon a node
description: >-
Sets `schedulable=false`: new explicit pins are rejected and `auto`
placement skips the node. Already-pinned services keep running and can
still reconcile — drain to evict them.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Node cordoned
content:
application/json:
schema:
type: object
properties:
id: { type: string }
schedulable: { type: boolean }
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/uncordon:
post:
tags:
- Agents
summary: Uncordon a node
description: Re-opens the node for placement (`schedulable=true`).
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Node uncordoned
content:
application/json:
schema:
type: object
properties:
id: { type: string }
schedulable: { type: boolean }
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/drain:
post:
tags:
- Agents
summary: Drain a node
description: >-
Cordons the node, removes every service container via the agent
command queue, and clears the affected services' `node_id` pins —
they fall back to the local host on next deploy and can be re-pinned
elsewhere. Requires the node to be online so it can acknowledge the
removals.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Node drained
content:
application/json:
schema:
type: object
properties:
id: { type: string }
schedulable: { type: boolean }
services_drained: { type: integer }
services_unpinned: { type: integer }
'404':
description: Agent not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Node is not online
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/agents/{id}/metrics:
get:
tags:
- Agents
summary: Agent metrics
description: Resource telemetry reported by the node agent.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Agent metrics and heartbeat history
content:
application/json:
schema:
type: object
/agents/{id}/commands:
get:
tags:
- Agents
summary: List agent commands
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
responses:
'200':
description: Command history for the agent
content:
application/json:
schema:
type: object
properties:
commands:
type: array
items:
$ref: '#/components/schemas/AgentCommand'
post:
tags:
- Agents
summary: Execute command on agent
description: Queue a command for the agent to pick up on its next poll.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ExecuteCommandRequest'
responses:
'201':
description: Command queued
content:
application/json:
schema:
type: object
properties:
command:
$ref: '#/components/schemas/AgentCommand'
/agents/{id}/commands/{commandId}:
get:
tags:
- Agents
summary: Get command status
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/AgentIdParam'
- name: commandId
in: path
required: true
schema:
type: string
responses:
'200':
description: Command status and result
content:
application/json:
schema:
type: object
properties:
command:
$ref: '#/components/schemas/AgentCommand'
'404':
description: Command not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Node agents — ingestion (token-authenticated, served under /api not /api/v1)
/api/agents/register:
servers:
- url: http://localhost:8080
post:
tags:
- Agents
summary: Register node agent
description: Agent self-registration. Requires the agent auth token (body or X-Agent-Token header).
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterAgentRequest'
responses:
'201':
description: Agent registered
content:
application/json:
schema:
type: object
properties:
agent:
$ref: '#/components/schemas/NodeAgent'
'401':
description: Invalid auth token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/agents/heartbeat:
servers:
- url: http://localhost:8080
post:
tags:
- Agents
summary: Agent heartbeat
description: Periodic heartbeat carrying resource usage and container counts.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AgentHeartbeat'
responses:
'200':
description: Heartbeat recorded
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
'401':
description: Invalid auth token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/agents/{id}/commands:
servers:
- url: http://localhost:8080
get:
tags:
- Agents
summary: Poll pending commands
description: Agent pulls its pending command queue.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Pending commands
content:
application/json:
schema:
type: object
properties:
commands:
type: array
items:
$ref: '#/components/schemas/AgentCommand'
/api/git/webhooks/{id}:
servers:
- url: http://localhost:8080
post:
tags:
- Git
summary: Push event receiver
description: >-
Public provider webhook endpoint. The HMAC signature against the stored
webhook secret replaces session auth: GitHub X-Hub-Signature-256,
Gitea X-Gitea-Signature, GitLab X-Gitlab-Token. Matching branch pushes
enqueue deployments for connected services.
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
description: Provider push payload (ref, repository, head_commit)
responses:
'202':
description: Push accepted; matched services queued for deployment
content:
application/json:
schema:
type: object
properties:
received:
type: boolean
branch:
type: string
deployments:
type: integer
ignored:
type: string
'400':
description: Invalid webhook ID or payload
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Invalid signature
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Webhook disabled
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Webhook or repository not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/git/github-app/webhook:
servers:
- url: http://localhost:8080
post:
tags:
- Git
summary: GitHub App webhook receiver
description: >-
Single app-level webhook all installed repositories deliver to
(configured via the manifest's hook_attributes). Verified with
X-Hub-Signature-256 against the provisioned webhook secret. Push
events enqueue deployments for services tracking the repo+branch.
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'202':
description: Event accepted
content:
application/json:
schema:
type: object
properties:
received:
type: boolean
branch:
type: string
deployments:
type: integer
ignored:
type: string
'401':
description: Invalid signature
'503':
description: GitHub App webhook secret not configured
/api/agents/{id}/commands/{commandId}/result:
servers:
- url: http://localhost:8080
post:
tags:
- Agents
summary: Report command result
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: commandId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- status
properties:
status:
type: string
enum: [completed, failed]
result:
type: string
error:
type: string
responses:
'200':
description: Result recorded
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
'401':
description: Invalid auth token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Preview environments
/projects/{id}/preview-environments:
get:
tags:
- Preview Environments
summary: List preview environments
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
responses:
'200':
description: Preview environments for the project
content:
application/json:
schema:
type: object
properties:
preview_environments:
type: array
items:
$ref: '#/components/schemas/PreviewEnvironment'
post:
tags:
- Preview Environments
summary: Create preview environment
description: Spin up a preview deployment for a branch or PR.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePreviewEnvironmentRequest'
responses:
'201':
description: Preview environment created
content:
application/json:
schema:
$ref: '#/components/schemas/PreviewEnvironment'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/preview-environments/{id}:
get:
tags:
- Preview Environments
summary: Get preview environment
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Preview environment
content:
application/json:
schema:
$ref: '#/components/schemas/PreviewEnvironment'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Preview Environments
summary: Update preview environment
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdatePreviewEnvironmentRequest'
responses:
'200':
description: Preview environment updated
content:
application/json:
schema:
$ref: '#/components/schemas/PreviewEnvironment'
delete:
tags:
- Preview Environments
summary: Delete preview environment
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Preview environment deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/preview-environments/{id}/promote:
post:
tags:
- Preview Environments
summary: Promote preview to production
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PromotePreviewEnvironmentRequest'
responses:
'200':
description: Preview promoted; returns the target deployment
content:
application/json:
schema:
type: object
/preview-environments/cleanup-expired:
post:
tags:
- Preview Environments
summary: Cleanup expired previews
description: Tear down preview environments past their TTL. Normally run by the scheduler; exposed for manual runs.
security:
- bearerAuth: []
responses:
'200':
description: Cleanup completed
content:
application/json:
schema:
type: object
properties:
cleaned:
type: integer
# Security
/security/scans:
post:
tags:
- Security
summary: Start security scan
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/StartSecurityScanRequest'
responses:
'201':
description: Scan started
content:
application/json:
schema:
$ref: '#/components/schemas/SecurityScan'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/security/scans/{id}:
get:
tags:
- Security
summary: Get security scan
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Scan status and results
content:
application/json:
schema:
$ref: '#/components/schemas/SecurityScan'
'404':
description: Scan not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects/{id}/security/history:
get:
tags:
- Security
summary: Project scan history
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
responses:
'200':
description: Security scans for the project
content:
application/json:
schema:
type: object
properties:
scans:
type: array
items:
$ref: '#/components/schemas/SecurityScan'
/projects/{id}/vulnerabilities:
get:
tags:
- Security
summary: Project vulnerabilities
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
responses:
'200':
description: Vulnerability findings for the project
content:
application/json:
schema:
type: object
properties:
vulnerabilities:
type: array
items:
$ref: '#/components/schemas/Vulnerability'
/vulnerabilities/{id}:
put:
tags:
- Security
summary: Update vulnerability
description: Mark a finding open/resolved/ignored with optional notes.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- status
properties:
status:
type: string
enum: [open, resolved, ignored]
notes:
type: string
responses:
'200':
description: Vulnerability updated
content:
application/json:
schema:
type: object
properties:
status:
type: string
/security/compliance/assess:
post:
tags:
- Security
summary: Start compliance assessment
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/StartComplianceAssessmentRequest'
responses:
'201':
description: Assessment started
content:
application/json:
schema:
type: object
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/security/compliance/reports/{id}:
get:
tags:
- Security
summary: Get compliance report
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Compliance report with per-control results
content:
application/json:
schema:
type: object
'404':
description: Report not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/security/compliance/frameworks:
get:
tags:
- Security
summary: List compliance frameworks
security:
- bearerAuth: []
responses:
'200':
description: Available compliance frameworks (SOC2, GDPR, ...)
content:
application/json:
schema:
type: object
properties:
frameworks:
type: array
items:
type: object
/security/compliance/gdpr/init:
post:
tags:
- Security
summary: Initialize GDPR framework
description: Seed the GDPR control set for compliance assessments.
security:
- bearerAuth: []
responses:
'200':
description: GDPR framework initialized
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/projects/{id}/security/metrics:
get:
tags:
- Security
summary: Project security metrics
description: 'Aggregate score: open findings by severity, latest scan, compliance status.'
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
responses:
'200':
description: Security metrics
content:
application/json:
schema:
type: object
/projects/{id}/security/audit-logs:
get:
tags:
- Security
summary: Security audit logs
description: Audit events scoped to a project (security-relevant actions).
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectIdParam'
responses:
'200':
description: Audit events
content:
application/json:
schema:
type: object
properties:
audit_logs:
type: array
items:
$ref: '#/components/schemas/AuditLog'
# Cron jobs
/cron-jobs:
get:
tags:
- Cron
summary: List cron jobs
parameters:
- name: project_id
in: query
schema:
type: string
format: uuid
- name: service_id
in: query
schema:
type: string
format: uuid
security:
- bearerAuth: []
responses:
'200':
description: Cron jobs
content:
application/json:
schema:
type: object
properties:
cron_jobs:
type: array
items:
$ref: '#/components/schemas/CronJob'
post:
tags:
- Cron
summary: Create cron job
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateCronJobRequest'
responses:
'201':
description: Cron job created
content:
application/json:
schema:
$ref: '#/components/schemas/CronJob'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/cron-jobs/{id}:
get:
tags:
- Cron
summary: Get cron job
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Cron job
content:
application/json:
schema:
$ref: '#/components/schemas/CronJob'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Cron
summary: Update cron job
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateCronJobRequest'
responses:
'200':
description: Cron job updated
content:
application/json:
schema:
$ref: '#/components/schemas/CronJob'
delete:
tags:
- Cron
summary: Delete cron job
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Cron job deleted
content:
application/json:
schema:
$ref: '#/components/schemas/MessageResponse'
/cron-jobs/{id}/executions:
get:
tags:
- Cron
summary: Cron execution history
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Executions for the cron job
content:
application/json:
schema:
type: object
properties:
executions:
type: array
items:
$ref: '#/components/schemas/CronExecution'
/cron-jobs/{id}/trigger:
post:
tags:
- Cron
summary: Trigger cron job now
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Execution started
content:
application/json:
schema:
$ref: '#/components/schemas/CronExecution'
# API Gateway (merged APwhy management surface)
/gateway/services:
get:
tags:
- Gateway
summary: List gateway services
description: Upstream services registered for key-gated proxying.
security:
- bearerAuth: []
responses:
'200':
description: Gateway services
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
post:
tags:
- Gateway
summary: Register gateway service
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayServiceRequest'
responses:
'201':
description: Service registered
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Name or route prefix already registered
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/gateway/services/{id}:
patch:
tags:
- Gateway
summary: Enable/disable gateway service
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
responses:
'200':
description: Service updated
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
/gateway/services/{id}/validate:
get:
tags:
- Gateway
summary: Validate upstream reachability
description: Probes the service's upstream health path and records the result.
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Validation result (reachable flag + status)
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
/gateway/keys:
get:
tags:
- Gateway
summary: List API keys
security:
- bearerAuth: []
responses:
'200':
description: API keys (hashes never returned)
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
post:
tags:
- Gateway
summary: Issue API key
description: The plaintext key is returned exactly once in this response.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayAPIKeyRequest'
responses:
'201':
description: Key issued — `key` field holds the plaintext token
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
'400':
description: Invalid input or unknown plan
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/gateway/keys/{id}:
patch:
tags:
- Gateway
summary: Enable/disable API key
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
responses:
'200':
description: Key updated
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
/gateway/analytics/ops:
get:
tags:
- Gateway
summary: Operations analytics
description: Error rates, incident counts, and uptime per gateway service.
security:
- bearerAuth: []
responses:
'200':
description: Ops analytics
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
/gateway/analytics/traffic:
get:
tags:
- Gateway
summary: Traffic analytics
description: Request volume timeseries per gateway service.
security:
- bearerAuth: []
responses:
'200':
description: Traffic analytics
content:
application/json:
schema:
$ref: '#/components/schemas/GatewayResponse'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Error:
type: object
properties:
error:
type: string
description: Error message
code:
type: string
description: Error code
details:
type: object
description: Additional error details
HealthResponse:
type: object
properties:
status:
type: string
example: ok
service:
type: string
example: containr-api
version:
type: string
example: 1.0.0
LoginRequest:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
description: User email address
password:
type: string
format: password
description: User password
LoginResponse:
type: object
properties:
token:
type: string
description: JWT access token
user:
$ref: '#/components/schemas/User'
RegisterRequest:
type: object
required:
- email
- password
- name
properties:
email:
type: string
format: email
description: User email address
password:
type: string
format: password
description: User password
name:
type: string
description: User display name
PlatformSettings:
type: object
properties:
signup_enabled:
type: boolean
description: Whether public account registration is open after bootstrap
cloudflare_tunnel:
type: object
properties:
token_set:
type: boolean
description: Whether a tunnel token is configured (value is never returned)
source:
type: string
enum: [app, env, none]
description: Where the active token comes from - in-app setting, env fallback, or unset
container:
type: string
description: cloudflared container state - running/exited/missing, or unavailable when Docker is unreachable
branding:
$ref: '#/components/schemas/Branding'
Branding:
type: object
description: White-label instance branding. Unset fields fall back to Containr defaults.
properties:
product_name:
type: string
logo_url:
type: string
favicon_url:
type: string
accent_color:
type: string
docs_url:
type: string
support_url:
type: string
User:
type: object
properties:
id:
type: string
description: User ID
email:
type: string
format: email
description: User email
name:
type: string
description: User display name
avatar_url:
type: string
description: Optional avatar image URL
is_admin:
type: boolean
description: True for the platform owner (first registered account)
created_at:
type: string
format: date-time
description: Account creation timestamp
updated_at:
type: string
format: date-time
description: Last update timestamp
UpdateUserRequest:
type: object
properties:
name:
type: string
description: User display name
email:
type: string
format: email
description: User email address
avatar_url:
type: string
description: Optional avatar image URL
AdminUser:
type: object
properties:
id:
type: string
email:
type: string
format: email
name:
type: string
avatar_url:
type: string
is_admin:
type: boolean
created_at:
type: string
Project:
type: object
properties:
id:
type: string
description: Project ID
name:
type: string
description: Project name
description:
type: string
description: Project description
owner_id:
type: string
description: Project owner ID
is_approved:
type: boolean
description: Whether the project is approved for public listing. New projects default to false and appear publicly only after admin approval.
created_at:
type: string
format: date-time
description: Project creation timestamp
updated_at:
type: string
format: date-time
description: Last update timestamp
stats:
$ref: '#/components/schemas/ProjectStats'
ProjectStats:
type: object
required:
- service_count
- deployment_count
- running_services
- last_deployment
properties:
service_count:
type: integer
deployment_count:
type: integer
running_services:
type: integer
last_deployment:
type: string
nullable: true
description: Timestamp of the most recent deployment
CreateProjectRequest:
type: object
required:
- name
properties:
name:
type: string
description: Project name
description:
type: string
description: Project description
UpdateProjectRequest:
type: object
properties:
name:
type: string
description: Project name
description:
type: string
description: Project description
ProjectsResponse:
type: object
properties:
projects:
type: array
items:
$ref: '#/components/schemas/Project'
pagination:
$ref: '#/components/schemas/Pagination'
Pagination:
type: object
properties:
page:
type: integer
description: Current page number
limit:
type: integer
description: Items per page
total:
type: integer
description: Total number of items
total_pages:
type: integer
description: Total number of pages
Service:
type: object
properties:
id:
type: string
format: uuid
description: Service ID
project_id:
type: string
format: uuid
description: Project ID
name:
type: string
description: Service name
type:
type: string
enum: [web, worker, database, cron]
description: Service type
status:
type: string
enum: [running, stopped, building, failed]
description: Service status
image:
type: string
description: Container image
command:
type: string
description: Start command
environment:
type: string
enum: [production, preview, development]
description: Deployment environment
git_repo:
type: string
description: Connected git repository
git_branch:
type: string
description: Connected git branch
build_path:
type: string
description: Build context path
cpu:
type: string
description: CPU allocation
memory:
type: string
description: Memory allocation
replicas:
type: integer
description: Desired replica count
port:
type: integer
description: Container port to expose (published host port, or Traefik when domain set)
domain:
type: string
description: Public hostname routed via Traefik
healthcheck_path:
type: string
description: HTTP path probed on port for container health
restart_policy:
type: string
description: Docker restart policy (default unless-stopped)
volumes:
type: array
items:
$ref: '#/components/schemas/ServiceVolume'
description: Volume/bind mounts applied to every replica
domains:
type: array
items:
$ref: '#/components/schemas/ServiceDomain'
description: All attached hostnames; `domain` is the derived default
maintenance_mode:
type: boolean
description: Redirect all traffic to the platform maintenance page
basic_auth:
type: array
items:
type: string
description: Basic-auth usernames gating the route (hashes never returned)
builder:
type: string
enum: [auto, railpack, nixpacks, dockerfile, static]
description: Build strategy; auto detects from repo contents
cpu_reserve:
type: string
description: Soft CPU reservation (fraction, e.g. 0.25 → ~256 CPU shares)
memory_reserve:
type: string
description: Soft memory reservation (e.g. 128Mi)
static_build_cmd:
type: string
description: Build command for the static builder (default "npm ci && npm run build")
static_dir:
type: string
description: Output directory for the static builder (default dist)
sleep_enabled:
type: boolean
description: Scale to zero after sleep_idle_minutes without inbound traffic; a wake placeholder answers requests while the service resumes
sleep_idle_minutes:
type: integer
description: Idle timeout in minutes before sleeping (1-1440, default 15)
node_id:
type: string
description: Node agent id this service is pinned to; empty/null = local Docker host. 'auto' on create/update resolves to the least-loaded online agent. Remote nodes run registry-pulled images only (no git builds, no Traefik domains).
node_name:
type: string
description: Display name of the pinned node agent (read-only)
public_url:
type: string
description: Computed public URL (published port or domain)
created_at:
type: string
format: date-time
description: Service creation timestamp
updated_at:
type: string
format: date-time
description: Last update timestamp
CreateServiceRequest:
type: object
required:
- name
- type
- environment
properties:
project_id:
type: string
format: uuid
description: Defaults to the project in the URL; must match when set
name:
type: string
description: Service name
type:
type: string
enum: [web, worker, database, cron]
description: Service type
image:
type: string
description: Container image
command:
type: string
description: Start command
environment:
type: string
enum: [production, preview, development]
description: Deployment environment
git_repo:
type: string
description: Git repository URL
git_branch:
type: string
description: Git branch
build_path:
type: string
description: Build context path
cpu:
type: string
description: CPU allocation
memory:
type: string
description: Memory allocation
replicas:
type: integer
description: Desired replica count
port:
type: integer
description: Container port to expose
domain:
type: string
description: Public hostname routed via Traefik
healthcheck_path:
type: string
description: HTTP path probed for container health
restart_policy:
type: string
description: Docker restart policy
volumes:
type: array
items:
$ref: '#/components/schemas/ServiceVolume'
description: Volume/bind mounts applied to every replica
builder:
type: string
enum: [auto, railpack, nixpacks, dockerfile, static]
description: Build strategy (default auto)
cpu_reserve:
type: string
description: Soft CPU reservation (fraction, e.g. 0.25)
memory_reserve:
type: string
description: Soft memory reservation (e.g. 128Mi)
static_build_cmd:
type: string
description: Build command for the static builder
static_dir:
type: string
description: Output directory for the static builder (default dist)
node_id:
type: string
description: Node agent id to pin to, 'auto' = least-loaded online agent; omit/empty = local host
UpdateServiceRequest:
type: object
properties:
name:
type: string
description: Service name
type:
type: string
enum: [web, worker, database, cron]
description: Service type
image:
type: string
description: Container image
command:
type: string
description: Start command
environment:
type: string
enum: [production, preview, development]
description: Deployment environment
git_repo:
type: string
description: Git repository URL
git_branch:
type: string
description: Git branch
build_path:
type: string
description: Build context path
cpu:
type: string
description: CPU allocation
memory:
type: string
description: Memory allocation
replicas:
type: integer
description: Desired replica count
port:
type: integer
description: Container port to expose
domain:
type: string
description: Public hostname routed via Traefik
healthcheck_path:
type: string
description: HTTP path probed for container health
restart_policy:
type: string
description: Docker restart policy
volumes:
type: array
items:
$ref: '#/components/schemas/ServiceVolume'
description: Replaces the entire mount list when present; [] clears all mounts. Takes effect on next deploy/reconcile.
maintenance_mode:
type: boolean
description: Redirect all traffic to the platform maintenance page
basic_auth:
type: array
items:
$ref: '#/components/schemas/BasicAuthCred'
description: Replaces all basic-auth credentials; [] clears the gate
builder:
type: string
enum: [auto, railpack, nixpacks, dockerfile, static]
description: Build strategy
cpu_reserve:
type: string
description: Soft CPU reservation (empty string clears)
memory_reserve:
type: string
description: Soft memory reservation (empty string clears)
static_build_cmd:
type: string
description: Build command for the static builder (empty string clears)
static_dir:
type: string
description: Output directory for the static builder (empty string clears)
sleep_enabled:
type: boolean
description: Scale to zero after sleep_idle_minutes without inbound traffic; a wake placeholder answers requests while resuming
sleep_idle_minutes:
type: integer
description: Idle timeout in minutes before sleeping (1-1440)
node_id:
type: string
description: Node agent id to pin to, 'auto' = least-loaded online agent, 'local' = run on the Containr host (clears the pin)
ServiceDomain:
type: object
properties:
id:
type: string
format: uuid
service_id:
type: string
format: uuid
domain:
type: string
is_default:
type: boolean
cert_type:
type: string
cert_status:
type: string
enum: [pending, issued, failed]
last_checked_at:
type: string
format: date-time
created_at:
type: string
format: date-time
DomainCheckResult:
type: object
properties:
domain:
type: string
status:
type: string
enum: [ok, wrong-target, pending]
description: ok = resolves to expected target (or no expectation configured), wrong-target = resolves elsewhere, pending = no DNS records
resolved:
type: array
items:
type: string
description: A/AAAA records resolved
BasicAuthCred:
type: object
required:
- username
- password
properties:
username:
type: string
password:
type: string
description: Plaintext on write — stored as bcrypt htpasswd; never returned
Registry:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
host:
type: string
description: Registry host matched against the image reference — ghcr.io, registry.example.com, docker.io for Docker Hub
username:
type: string
has_password:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
RegistryRequest:
type: object
required:
- name
- host
properties:
name:
type: string
host:
type: string
username:
type: string
password:
type: string
description: Plaintext on write — stored encrypted; never returned. Empty on update keeps the stored credential.
ServiceVolume:
type: object
required:
- source
- target
properties:
type:
type: string
enum: [volume, bind]
default: volume
description: volume = docker named volume, bind = host path
source:
type: string
description: Volume name or host path
target:
type: string
description: Absolute container path
read_only:
type: boolean
default: false
VolumeInfo:
type: object
properties:
name:
type: string
driver:
type: string
mountpoint:
type: string
scope:
type: string
in_use:
type: boolean
used_by:
type: array
items:
type: string
description: Container names mounting this volume
created_at:
type: string
format: date-time
Deployment:
type: object
properties:
id:
type: string
description: Deployment ID
service_id:
type: string
description: Service ID
commit_hash:
type: string
description: Source commit hash
status:
type: string
description: Deployment status
image_name:
type: string
description: Deployed image name
image_tag:
type: string
description: Deployed image tag
build_log:
type: string
description: Build log content
runtime_log:
type: string
description: Runtime log content
error:
type: string
description: Deployment error
started_at:
type: string
format: date-time
description: Deployment start timestamp
completed_at:
type: string
format: date-time
description: Deployment completion timestamp
created_at:
type: string
format: date-time
description: Deployment creation timestamp
updated_at:
type: string
format: date-time
description: Deployment update timestamp
DeploymentListResponse:
type: object
properties:
deployments:
type: array
items:
$ref: '#/components/schemas/Deployment'
CreateDeploymentRequest:
type: object
properties:
commit_hash:
type: string
description: Source commit hash
branch:
type: string
description: Source branch
trigger:
type: string
description: Trigger source (manual, restart, webhook)
env_vars:
type: object
additionalProperties:
type: string
description: Runtime environment variable overrides
no_cache:
type: boolean
description: Build without Docker layer cache
RollbackDeploymentResponse:
type: object
properties:
deployment:
$ref: '#/components/schemas/Deployment'
message:
type: string
description: Rollback result message
ServiceLogEntry:
type: object
properties:
timestamp:
type: string
format: date-time
description: Log timestamp
message:
type: string
description: Log message
stream:
type: string
description: Log stream identifier
ServiceLogsResponse:
type: object
properties:
logs:
type: array
items:
$ref: '#/components/schemas/ServiceLogEntry'
message:
type: string
description: Additional context when logs are unavailable
DeploymentLogsResponse:
type: object
properties:
logs:
type: array
items:
$ref: '#/components/schemas/ServiceLogEntry'
build_log:
type: string
description: Build log text
runtime_log:
type: string
description: Runtime log text
BuildStatus:
type: object
properties:
id:
type: string
description: Build ID
project_id:
type: string
description: Project ID
service_id:
type: string
description: Service ID
status:
type: string
enum: [pending, running, success, failed, cancelled]
description: Build status
progress:
type: integer
minimum: 0
maximum: 100
description: Build progress percentage
started_at:
type: string
format: date-time
description: Build start time
completed_at:
type: string
format: date-time
description: Build completion time
image_name:
type: string
description: Target image name
image_tag:
type: string
description: Target image tag
size:
type: integer
format: int64
description: Built image size in bytes
error:
type: string
description: Build error message
log:
type: string
description: Build logs
metadata:
type: object
additionalProperties:
type: string
description: Additional build metadata
StartBuildRequest:
type: object
required:
- image_name
- image_tag
properties:
build_type:
type: string
description: Build system type; if omitted backend auto-detects
enum: [railpack, nixpacks, dockerfile, prebuilt]
source_path:
type: string
description: Local source path for build context
prebuilt_image:
type: string
description: Existing image reference when using prebuilt mode
image_name:
type: string
description: Output image name
image_tag:
type: string
description: Output image tag
registry_url:
type: string
description: Optional registry URL for push target
build_command:
type: string
description: Optional build command override
start_command:
type: string
description: Optional runtime command override
environment:
type: object
additionalProperties:
type: string
description: Build environment variables
build_args:
type: object
additionalProperties:
type: string
description: Build-time arguments
labels:
type: object
additionalProperties:
type: string
description: Image labels
project_id:
type: string
description: Associated project ID
service_id:
type: string
description: Associated service ID
branch:
type: string
description: Git branch
commit:
type: string
description: Git commit SHA
StartBuildResponse:
type: object
properties:
id:
type: string
description: Build ID
status:
type: string
enum: [pending, running, success, failed, cancelled]
description: Initial build status
image_name:
type: string
description: Requested image name
image_tag:
type: string
description: Requested image tag
size:
type: integer
format: int64
description: Result image size in bytes when available
digest:
type: string
description: Result image digest when available
build_time:
type: string
format: date-time
description: Build request timestamp
success:
type: boolean
description: Whether request acceptance succeeded
error:
type: string
description: Error details when acceptance failed
BuildListResponse:
type: object
properties:
builds:
type: array
items:
$ref: '#/components/schemas/BuildStatus'
total:
type: integer
description: Total matching builds
page:
type: integer
description: Current page number
limit:
type: integer
description: Page size
BuildCancelResponse:
type: object
properties:
message:
type: string
description: Cancellation result message
ServiceTemplate:
type: object
properties:
id:
type: string
description: Template ID
name:
type: string
description: Template display name
description:
type: string
description: Template description
category:
type: string
description: Template category
logo:
type: string
description: Template logo URL
config:
type: string
description: Raw template config JSON string
variables:
type: string
description: Raw template variables JSON string
is_official:
type: boolean
description: Whether template is an official preset
owner_id:
type: string
nullable: true
description: Owning user ID for user-created templates; null for official presets
is_public:
type: boolean
description: Whether a user-created template is published to the public catalog
source:
type: string
description: 'Catalog origin: absent for local/official templates; "registry" for entries merged from CONTAINR_TEMPLATE_REGISTRY_URL. Deploying a registry template materializes a local copy first.'
created_at:
type: string
format: date-time
description: Creation timestamp
updated_at:
type: string
format: date-time
description: Last update timestamp
TemplateWriteRequest:
type: object
required:
- name
- config
properties:
name:
type: string
description: Template display name
description:
type: string
description: Template description
category:
type: string
description: Template category (web, database, cache, queue, monitoring, storage, app, other)
logo:
type: string
description: Template logo URL
config:
type: object
description: Template config object (type, runtime, commands, port, environment)
variables:
type: array
items:
$ref: '#/components/schemas/TemplateVariable'
description: Configurable variables exposed at deploy time
is_public:
type: boolean
description: Publish this template to the public catalog (visible anonymously)
TemplateConfig:
type: object
properties:
version:
type: integer
description: Config version — 2 when services[] is used
type:
type: string
description: Service type for created service
runtime:
type: string
description: Runtime or base image
build_command:
type: string
description: Build command
start_command:
type: string
description: Start command
port:
type: integer
description: Service port
health_check:
type: string
description: Health check path
environment:
type: object
additionalProperties:
type: string
description: Default environment variables
dockerfile:
type: string
description: Optional dockerfile path
nixpacks_config:
type: object
additionalProperties:
type: string
description: Optional nixpacks-specific config
services:
type: array
description: |
v2 graph members. When non-empty, the flat fields above are
ignored and deploy creates the whole graph in dependency order.
items:
$ref: '#/components/schemas/TemplateServiceSpec'
TemplateServiceSpec:
type: object
required:
- key
- type
properties:
key:
type: string
description: Member key — DNS alias on the project network and the target of {{service.<key>.*}} refs
name:
type: string
description: Display/deployed name (defaults to key)
type:
type: string
enum: [web, worker, cron, database]
runtime:
type: string
description: Image reference (web/worker/cron) or managed engine (database)
repo:
type: string
description: Git repository URL — when set, the member builds from source
branch:
type: string
build_command:
type: string
start_command:
type: string
port:
type: integer
health_check:
type: string
builder:
type: string
enum: [auto, nixpacks, dockerfile, static]
environment:
type: object
additionalProperties:
type: string
description: |
Env vars. Values support {{secret}}, {{secret(N)}}, {{random:N}},
{{VAR}}, {{VAR:-default}} and {{service.<key>.<prop>}} where prop
is host, port, url, user, password or database.
volumes:
type: array
items:
$ref: '#/components/schemas/ServiceVolume'
depends_on:
type: array
items:
type: string
description: Member keys that must be created first
TemplatePlanMember:
type: object
properties:
key:
type: string
name:
type: string
type:
type: string
runtime:
type: string
port:
type: integer
depends_on:
type: array
items:
type: string
environment:
type: object
additionalProperties:
type: string
TemplateVariable:
type: object
properties:
key:
type: string
description: Variable key
label:
type: string
description: Display label
default:
type: string
description: Default value
required:
type: boolean
description: Whether variable is required
secret:
type: boolean
description: Whether variable is sensitive
description:
type: string
description: Variable description
TemplateDetailResponse:
type: object
properties:
template:
$ref: '#/components/schemas/ServiceTemplate'
config:
$ref: '#/components/schemas/TemplateConfig'
variables:
type: array
items:
$ref: '#/components/schemas/TemplateVariable'
DeployTemplateRequest:
type: object
required:
- project_id
- name
properties:
project_id:
type: string
description: Target project ID
name:
type: string
description: Name for the created service
plan:
type: string
enum: [hobby, starter, standard, business]
description: Optional managed database plan for database templates
region:
type: string
description: Optional managed database region for database templates
variables:
type: object
additionalProperties:
type: string
description: Variable overrides for template deployment
DeployTemplateResponse:
type: object
properties:
resource:
type: string
enum: [service, database, stack]
description: Type of resource created by template deployment
service_id:
type: string
description: Newly created service ID (set for non-database templates)
database_id:
type: string
description: Newly created managed database ID (set for database templates)
created:
type: array
description: Created resources (set for graph templates — resource=stack)
items:
type: object
properties:
key:
type: string
kind:
type: string
enum: [service, database]
id:
type: string
name:
type: string
deployment_id:
type: string
message:
type: string
description: Deployment result message
AuditLog:
type: object
properties:
id:
type: string
description: Audit log ID
user_id:
type: string
description: User ID that triggered action
user_email:
type: string
description: User email snapshot
resource:
type: string
description: Resource type
resource_id:
type: string
description: Resource ID
action:
type: string
description: Action type
details:
type: string
description: JSON-encoded action details
ip_address:
type: string
description: Source IP address
user_agent:
type: string
description: Source user agent
severity:
type: string
enum: [info, success, warning, error]
description: Event severity for feed display
category:
type: string
description: Coarse category (service, deployment, project, user, security, system, …)
label:
type: string
description: Human-readable event label
created_at:
type: string
format: date-time
description: Timestamp when the audit log entry was created
Notification:
type: object
properties:
id:
type: string
format: uuid
kind:
type: string
title:
type: string
body:
type: string
resource_type:
type: string
resource_id:
type: string
read_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
NotificationListResponse:
type: object
properties:
notifications:
type: array
items:
$ref: '#/components/schemas/Notification'
unread:
type: integer
OutboundWebhook:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
url:
type: string
secret:
type: string
description: Only present on create/update responses
events:
type: array
items:
type: string
headers:
type: object
additionalProperties:
type: string
enabled:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
WebhookDelivery:
type: object
properties:
id:
type: string
format: uuid
webhook_id:
type: string
format: uuid
event:
type: string
payload:
type: object
additionalProperties: true
status:
type: string
enum: [pending, success, failed]
response_status:
type: integer
nullable: true
response_body:
type: string
nullable: true
attempts:
type: integer
duration_ms:
type: integer
nullable: true
created_at:
type: string
format: date-time
delivered_at:
type: string
format: date-time
nullable: true
AuditLogListResponse:
type: object
properties:
audit_logs:
type: array
items:
$ref: '#/components/schemas/AuditLog'
Database:
type: object
properties:
id:
type: string
description: Database ID
name:
type: string
description: Database name
type:
type: string
enum: [postgresql, redis, mysql, mariadb, mongodb, clickhouse, dragonfly]
description: Database type
status:
type: string
enum: [running, stopped, building, error]
description: Database status
connection_url:
type: string
description: Database connection URL
version:
type: string
description: Database version
plan:
type: string
enum: [hobby, starter, standard, business]
description: Provisioning plan
region:
type: string
description: Provisioning region
backup_schedule:
type: string
description: Cron expression for automatic backups, empty when unset
provider:
type: string
enum: [managed, external]
description: managed = Containr-provisioned container; external = registered connection to a database hosted elsewhere
public_port:
type: boolean
description: managed only — bind the database port on all interfaces instead of 127.0.0.1; toggling recreates the container
backup_target_id:
type: string
description: S3-compatible backup target receiving this database's archives, empty when local-only
external:
$ref: '#/components/schemas/DatabaseExternal'
next_backup_at:
type: string
format: date-time
description: Next scheduled backup run
metrics:
$ref: '#/components/schemas/DatabaseMetrics'
backups:
$ref: '#/components/schemas/DatabaseBackupConfig'
settings:
$ref: '#/components/schemas/DatabaseSettings'
created_at:
type: string
format: date-time
description: Database creation timestamp
updated_at:
type: string
format: date-time
description: Last update timestamp
CreateDatabaseRequest:
type: object
required:
- name
- type
- plan
- region
properties:
name:
type: string
description: Database name
type:
type: string
enum: [postgresql, redis, mysql, mariadb, mongodb, clickhouse, dragonfly]
description: Database type
plan:
type: string
enum: [hobby, starter, standard, business]
description: Database plan
region:
type: string
description: Database region
public_port:
type: boolean
description: Bind the database port on all interfaces (default 127.0.0.1)
DatabaseExternal:
type: object
properties:
host:
type: string
port:
type: integer
database:
type: string
username:
type: string
has_password:
type: boolean
ssl:
type: boolean
ExternalDatabaseRequest:
type: object
required:
- type
- host
properties:
name:
type: string
description: Display name (required for register, unused for probes)
type:
type: string
enum: [postgresql, redis, mysql, mariadb, mongodb, clickhouse, dragonfly]
host:
type: string
port:
type: integer
description: Defaults to the engine's standard port
database:
type: string
username:
type: string
password:
type: string
description: Stored encrypted; never returned
ssl:
type: boolean
UpdateDatabaseRequest:
type: object
properties:
name:
type: string
description: Updated database name
plan:
type: string
enum: [hobby, starter, standard, business]
description: Updated database plan
backup_schedule:
type: string
nullable: true
description: Cron expression for automatic backups; empty string clears the schedule
public_port:
type: boolean
description: Toggle the published port between 127.0.0.1 and all interfaces; recreates the managed container
backup_target_id:
type: string
nullable: true
description: Assign a backup target for offsite archives; empty string clears
DatabaseActionRequest:
type: object
required:
- action
properties:
action:
type: string
enum: [start, stop, restart]
description: Action to execute
DatabaseRestoreRequest:
type: object
required:
- backup_id
properties:
backup_id:
type: string
description: Backup identifier to restore
DatabaseCreateResponse:
type: object
properties:
id:
type: string
description: Database ID
message:
type: string
status:
type: string
enum: [building]
DatabaseActionResponse:
type: object
properties:
message:
type: string
status:
type: string
enum: [running, stopped, building, error]
DatabaseBackupCreateResponse:
type: object
properties:
backup_id:
type: string
message:
type: string
status:
type: string
enum: [in_progress]
DatabaseListResponse:
type: object
properties:
databases:
type: array
items:
$ref: '#/components/schemas/Database'
DatabaseMetrics:
type: object
properties:
cpu:
type: number
memory:
type: number
storage:
type: number
connections:
type: integer
read_iops:
type: integer
write_iops:
type: integer
network_in:
type: number
network_out:
type: number
DatabaseBackup:
type: object
properties:
id:
type: string
created_at:
type: string
format: date-time
size:
type: string
status:
type: string
enum: [completed, failed, in_progress]
remote:
type: boolean
description: Archive also shipped to the database's configured backup target
BackupTarget:
type: object
properties:
id:
type: string
name:
type: string
endpoint:
type: string
description: Bare host[:port] — scheme comes from use_tls
bucket:
type: string
region:
type: string
prefix:
type: string
has_credentials:
type: boolean
use_tls:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BackupTargetRequest:
type: object
required:
- endpoint
- bucket
properties:
name:
type: string
endpoint:
type: string
bucket:
type: string
region:
type: string
prefix:
type: string
access_key:
type: string
description: Stored encrypted; never returned. Empty on update keeps stored credentials.
secret_key:
type: string
description: Stored encrypted; never returned. Empty on update keeps stored credentials.
use_tls:
type: boolean
default: true
DatabaseBackupConfig:
type: object
properties:
enabled:
type: boolean
last_backup:
type: string
format: date-time
retention:
type: integer
next_backup:
type: string
format: date-time
backups:
type: array
items:
$ref: '#/components/schemas/DatabaseBackup'
DatabaseSettings:
type: object
properties:
max_connections:
type: integer
timeout:
type: integer
ssl:
type: boolean
logging:
type: boolean
MessageResponse:
type: object
properties:
message:
type: string
GitProvider:
type: object
required:
- id
- name
- display_name
- api_url
- webhook_url
- user_id
- created_at
- updated_at
properties:
id:
type: string
description: Provider ID
name:
type: string
enum: [github, gitlab, bitbucket, gitea, github_app]
description: Provider type identifier
display_name:
type: string
description: Provider display name
api_url:
type: string
description: Custom API base URL (self-hosted providers)
webhook_url:
type: string
description: Webhook callback URL registered on the provider
user_id:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
description: Access tokens are never serialized in responses.
CreateGitProviderRequest:
type: object
required:
- name
- display_name
- access_token
properties:
name:
type: string
enum: [github, gitlab, bitbucket, gitea, github_app]
description: Provider type identifier
display_name:
type: string
description: Provider display name
access_token:
type: string
description: Personal access token (stored encrypted, never returned)
api_url:
type: string
description: Custom API base URL for self-hosted providers
GitBranch:
type: object
required:
- name
- protected
properties:
name:
type: string
protected:
type: boolean
GitRepository:
type: object
required:
- id
- provider_id
- name
- full_name
- description
- clone_url
- webhook_url
- default_branch
- is_private
- user_id
- created_at
- updated_at
properties:
id:
type: string
description: Repository ID
provider_id:
type: string
name:
type: string
description: Repository name
full_name:
type: string
description: Repository full name (owner/repo)
description:
type: string
description: Repository description
clone_url:
type: string
description: Clone URL
webhook_url:
type: string
default_branch:
type: string
description: Default branch
is_private:
type: boolean
description: Whether repository is private
user_id:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
ManualUserCreateRequest:
type: object
required:
- email
- password
- name
properties:
email:
type: string
format: email
password:
type: string
format: password
minLength: 8
maxLength: 128
name:
type: string
minLength: 2
maxLength: 255
ServiceVariable:
type: object
properties:
id:
type: string
format: uuid
service_id:
type: string
format: uuid
key:
type: string
value:
type: string
description: Masked as ******** when is_secret is true
is_secret:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
VariableInput:
type: object
required:
- key
properties:
key:
type: string
value:
type: string
is_secret:
type: boolean
UpdateVariablesRequest:
type: object
required:
- variables
properties:
variables:
type: array
items:
$ref: '#/components/schemas/VariableInput'
redeploy:
type: boolean
description: Queue a service redeploy after saving so running containers pick up the new variables
ConnectGitHubAppRequest:
type: object
required:
- installation_id
properties:
installation_id:
type: integer
format: int64
description: GitHub App installation ID from the install callback
display_name:
type: string
ConnectGitRepoRequest:
type: object
required:
- provider_id
- repo_full_name
properties:
provider_id:
type: string
repo_full_name:
type: string
description: owner/repo
CreateWebhookRequest:
type: object
required:
- repo_id
- events
properties:
repo_id:
type: string
events:
type: array
items:
type: string
example: [push, pull_request]
branch:
type: string
GitWebhook:
type: object
properties:
id:
type: string
repo_id:
type: string
provider_id:
type: string
events:
type: array
items:
type: string
description: Subscribed provider events
branch:
type: string
description: Branch filter for push events
active:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
description: Webhook secrets are never serialized in responses.
BuildRequest:
type: object
required:
- image_name
- image_tag
properties:
build_type:
type: string
description: dockerfile | railpack | prebuilt — auto-detected when empty
source_path:
type: string
prebuilt_image:
type: string
image_name:
type: string
image_tag:
type: string
registry_url:
type: string
build_command:
type: string
start_command:
type: string
environment:
type: object
additionalProperties:
type: string
build_args:
type: object
additionalProperties:
type: string
labels:
type: object
additionalProperties:
type: string
project_id:
type: string
service_id:
type: string
branch:
type: string
commit:
type: string
UpgradeStatus:
type: object
properties:
image_ref:
type: string
registry:
type: string
docker_available:
type: boolean
installed:
type: boolean
digest:
type: string
size:
type: integer
format: int64
auth_configured:
type: boolean
message:
type: string
HostMonitoring:
type: object
properties:
hostname:
type: string
os:
type: string
architecture:
type: string
cpu:
type: object
properties:
cores:
type: integer
memory:
type: object
properties:
total:
type: integer
format: int64
used:
type: integer
format: int64
available:
type: integer
format: int64
usage_percent:
type: number
storage:
type: object
properties:
path:
type: string
total:
type: integer
format: int64
used:
type: integer
format: int64
available:
type: integer
format: int64
usage_percent:
type: number
load:
type: object
properties:
load_1m:
type: number
load_5m:
type: number
load_15m:
type: number
uptime_seconds:
type: integer
format: int64
docker_available:
type: boolean
docker:
type: object
description: Docker daemon details when available
properties:
containers:
type: integer
images:
type: integer
driver:
type: string
server:
type: string
os:
type: string
scope:
type: string
description: What the telemetry measures — `host` for a native daemon, `docker-desktop-vm` when Docker runs inside a Desktop VM.
enum: [host, docker-desktop-vm]
collected_at:
type: string
format: date-time
ServiceInstanceMetrics:
type: object
required:
- container_id
- name
- state
- cpu_percent
- memory_usage_bytes
- memory_limit_bytes
- network_rx_bytes
- network_tx_bytes
- started_at
properties:
container_id:
type: string
name:
type: string
state:
type: string
cpu_percent:
type: number
memory_usage_bytes:
type: integer
format: int64
memory_limit_bytes:
type: integer
format: int64
network_rx_bytes:
type: integer
format: int64
network_tx_bytes:
type: integer
format: int64
started_at:
type: string
format: date-time
ServiceMetrics:
type: object
required:
- service_id
- status
- instances
- cpu_percent
- memory_usage_bytes
- memory_limit_bytes
- network_rx_bytes
- network_tx_bytes
- collected_at
properties:
service_id:
type: string
status:
type: string
enum: [ok, no_containers, docker_unavailable]
instances:
type: array
items:
$ref: '#/components/schemas/ServiceInstanceMetrics'
cpu_percent:
type: number
memory_usage_bytes:
type: integer
format: int64
memory_limit_bytes:
type: integer
format: int64
network_rx_bytes:
type: integer
format: int64
network_tx_bytes:
type: integer
format: int64
collected_at:
type: string
format: date-time
ScalingPolicy:
type: object
required:
- service_id
- min_replicas
- max_replicas
properties:
service_id:
type: string
min_replicas:
type: integer
minimum: 1
max_replicas:
type: integer
minimum: 1
target_cpu:
type: number
description: Target CPU utilization percent
target_memory:
type: number
description: Target memory utilization percent
scale_up_cooldown:
type: integer
description: Nanoseconds (Go duration serialized as integer)
scale_down_cooldown:
type: integer
scale_up_step:
type: integer
scale_down_step:
type: integer
metrics:
type: array
items:
type: string
thresholds:
type: object
additionalProperties:
type: number
enabled:
type: boolean
cost_optimization:
type: object
ScalingEvent:
type: object
properties:
id:
type: string
service_id:
type: string
from_replicas:
type: integer
to_replicas:
type: integer
reason:
type: string
trigger:
type: string
description: auto | manual
created_at:
type: string
format: date-time
FailoverPolicy:
type: object
required:
- service_id
properties:
service_id:
type: string
enabled:
type: boolean
min_healthy_nodes:
type: integer
max_failures:
type: integer
failover_timeout:
type: integer
description: Nanoseconds
recovery_timeout:
type: integer
description: Nanoseconds
failover_strategy:
type: string
backup_nodes:
type: array
items:
type: string
health_check_config:
type: object
HealthCheck:
type: object
properties:
id:
type: string
service_id:
type: string
node_id:
type: string
type:
type: string
description: http | tcp | exec
config:
type: object
last_check:
type: string
format: date-time
status:
type: string
AlertRule:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
enabled:
type: boolean
condition:
type: object
description: metric, operator, threshold, duration
severity:
type: string
enum: [info, warning, critical]
labels:
type: object
additionalProperties:
type: string
annotations:
type: object
additionalProperties:
type: string
notifiers:
type: array
items:
type: string
cooldown:
type: integer
description: Nanoseconds
Notifier:
type: object
properties:
id:
type: string
type:
type: string
description: webhook | slack | email | discord
config:
type: object
NotifierRequest:
type: object
required:
- type
- config
properties:
id:
type: string
type:
type: string
config:
type: object
NodeAgent:
type: object
properties:
id:
type: string
name:
type: string
hostname:
type: string
ip_address:
type: string
port:
type: integer
status:
type: string
description: online | offline | connecting | error
version:
type: string
capabilities:
$ref: '#/components/schemas/AgentCapabilities'
resources:
$ref: '#/components/schemas/NodeResources'
metadata:
type: object
additionalProperties: true
auto_prune:
type: boolean
description: Enqueue a bounded docker prune on this node once per day.
schedulable:
type: boolean
description: >-
False on a cordoned/drained node — `auto` placement skips it and
new explicit pins are rejected.
last_heartbeat:
type: string
format: date-time
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
AgentAuthToken:
type: object
properties:
id:
type: string
format: uuid
label:
type: string
created_at:
type: string
format: date-time
last_used_at:
type: string
format: date-time
revoked:
type: boolean
revoked_at:
type: string
format: date-time
required:
- id
- label
- created_at
- revoked
AgentAuthTokenCreated:
allOf:
- $ref: '#/components/schemas/AgentAuthToken'
- type: object
properties:
token:
type: string
description: Raw token value, returned exactly once at creation
required:
- token
CreateAgentTokenRequest:
type: object
properties:
label:
type: string
description: Human-readable label for the token (e.g. node name)
UserToken:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
key_prefix:
type: string
description: First 12 chars of the token, for identification in lists
scope:
type: string
enum: [read, write, admin]
expires_at:
type: string
format: date-time
last_used_at:
type: string
format: date-time
created_at:
type: string
format: date-time
required:
- id
- name
- key_prefix
- scope
- created_at
UserTokenCreated:
allOf:
- $ref: '#/components/schemas/UserToken'
- type: object
properties:
token:
type: string
description: Raw cnp_ token value, returned exactly once at creation
required:
- token
CreateUserTokenRequest:
type: object
properties:
name:
type: string
description: Human-readable label (e.g. "laptop cli", "ci deploy")
scope:
type: string
enum: [read, write, admin]
default: write
description: read = GET/HEAD only; write = all non-admin routes; admin = everything (requires admin account)
expires_in_days:
type: integer
minimum: 0
maximum: 3650
description: 0 or omitted = never expires
required:
- name
AgentCapabilities:
type: object
properties:
container_runtimes:
type: array
items:
type: string
supported_architectures:
type: array
items:
type: string
max_containers:
type: integer
storage_driver:
type: string
network_plugins:
type: array
items:
type: string
features:
type: array
items:
type: string
NodeResources:
type: object
properties:
cpu:
type: object
properties:
cores:
type: integer
allocation:
type: number
description: Allocated CPU percentage
usage:
type: number
description: Current usage percentage
memory:
type: object
properties:
total:
type: integer
format: int64
allocated:
type: integer
format: int64
used:
type: integer
format: int64
available:
type: integer
format: int64
storage:
type: object
properties:
total:
type: integer
format: int64
allocated:
type: integer
format: int64
used:
type: integer
format: int64
available:
type: integer
format: int64
network:
type: object
properties:
interfaces:
type: array
items:
type: object
properties:
name:
type: string
ip_address:
type: string
mac_address:
type: string
speed:
type: integer
status:
type: string
bandwidth:
type: object
properties:
inbound:
type: integer
format: int64
description: Bytes per second
outbound:
type: integer
format: int64
description: Bytes per second
RegisterAgentRequest:
type: object
required:
- name
- hostname
- ip_address
- port
- capabilities
properties:
name:
type: string
hostname:
type: string
ip_address:
type: string
port:
type: integer
capabilities:
$ref: '#/components/schemas/AgentCapabilities'
auth_token:
type: string
description: May also be sent via the X-Agent-Token header
mesh:
type: object
additionalProperties:
type: string
description: Overlay-network interface IPs (tailscale/netbird/zerotier/wireguard). Stored under agent metadata.mesh; authoritative — send an empty object when no mesh interfaces exist.
AgentHeartbeat:
type: object
properties:
agent_id:
type: string
status:
type: string
resources:
$ref: '#/components/schemas/NodeResources'
container_count:
type: integer
system_load:
type: object
uptime:
type: integer
version:
type: string
AgentCommand:
type: object
properties:
id:
type: string
node_agent_id:
type: string
type:
type: string
payload:
type: object
status:
type: string
description: pending | running | completed | failed
result:
type: string
error:
type: string
created_at:
type: string
format: date-time
completed_at:
type: string
format: date-time
ExecuteCommandRequest:
type: object
required:
- type
properties:
type:
type: string
payload:
type: object
ContainerInstance:
type: object
properties:
id:
type: string
agent_id:
type: string
project_id:
type: string
service_id:
type: string
name:
type: string
image:
type: string
status:
type: string
resources:
type: object
ports:
type: array
items:
type: object
created_at:
type: string
format: date-time
CreateContainerRequest:
type: object
required:
- name
- image
- project_id
- service_id
- resources
properties:
name:
type: string
image:
type: string
project_id:
type: string
service_id:
type: string
resources:
type: object
description: cpu/memory limits
ports:
type: array
items:
type: object
properties:
host_port:
type: integer
container_port:
type: integer
protocol:
type: string
environment:
type: object
additionalProperties:
type: string
volumes:
type: array
items:
type: object
networks:
type: array
items:
type: string
restart_policy:
type: object
health_check:
type: object
PreviewEnvironment:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
service_id:
type: string
format: uuid
branch_name:
type: string
pr_number:
type: integer
environment:
type: string
description: Generated name, e.g. preview-{branch}-{ts}
status:
type: string
enum: [building, running, failed, stopped, expired]
url:
type: string
expires_at:
type: string
format: date-time
deployment_id:
type: string
format: uuid
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
CreatePreviewEnvironmentRequest:
type: object
required:
- service_id
- branch_name
properties:
project_id:
type: string
format: uuid
service_id:
type: string
format: uuid
branch_name:
type: string
pr_number:
type: integer
ttl_hours:
type: integer
minimum: 1
maximum: 168
UpdatePreviewEnvironmentRequest:
type: object
properties:
status:
type: string
enum: [building, running, failed, stopped, expired]
url:
type: string
expires_at:
type: string
format: date-time
ttl_hours:
type: integer
minimum: 1
maximum: 168
PromotePreviewEnvironmentRequest:
type: object
required:
- target_environment
properties:
target_environment:
type: string
enum: [production, development]
create_backup:
type: boolean
StartSecurityScanRequest:
type: object
required:
- project_id
- scan_type
properties:
project_id:
type: string
service_id:
type: string
scan_type:
type: string
enum: [dependency, configuration, comprehensive]
SecurityScan:
type: object
properties:
id:
type: string
project_id:
type: string
service_id:
type: string
scan_type:
type: string
status:
type: string
description: pending | running | completed | failed
findings_count:
type: integer
started_at:
type: string
format: date-time
completed_at:
type: string
format: date-time
Vulnerability:
type: object
properties:
id:
type: string
type:
type: string
severity:
type: string
enum: [low, medium, high, critical]
title:
type: string
description:
type: string
service_id:
type: string
project_id:
type: string
status:
type: string
enum: [open, resolved, ignored]
found_at:
type: string
format: date-time
resolved_at:
type: string
format: date-time
StartComplianceAssessmentRequest:
type: object
required:
- project_id
- framework_id
properties:
project_id:
type: string
framework_id:
type: string
CronJob:
type: object
properties:
id:
type: string
project_id:
type: string
service_id:
type: string
name:
type: string
schedule:
type: string
description: Cron expression
command:
type: string
timezone:
type: string
enabled:
type: boolean
last_run_at:
type: string
format: date-time
next_run_at:
type: string
format: date-time
last_status:
type: string
last_output:
type: string
retention:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
CronExecution:
type: object
properties:
id:
type: string
cron_job_id:
type: string
started_at:
type: string
format: date-time
finished_at:
type: string
format: date-time
status:
type: string
output:
type: string
error:
type: string
CreateCronJobRequest:
type: object
required:
- project_id
- service_id
- name
- schedule
- command
properties:
project_id:
type: string
service_id:
type: string
name:
type: string
schedule:
type: string
command:
type: string
timezone:
type: string
enabled:
type: boolean
retention:
type: integer
UpdateCronJobRequest:
type: object
properties:
name:
type: string
schedule:
type: string
command:
type: string
timezone:
type: string
enabled:
type: boolean
retention:
type: integer
GatewayService:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
upstream_url:
type: string
route_prefix:
type: string
enabled:
type: boolean
rpm_limit:
type: integer
monthly_quota:
type: integer
health_path:
type: string
last_validated_at:
type: string
format: date-time
last_validation_status:
type: string
created_at:
type: string
format: date-time
GatewayServiceRequest:
type: object
required:
- name
- upstreamUrl
- routePrefix
properties:
name:
type: string
maxLength: 100
upstreamUrl:
type: string
format: uri
maxLength: 500
routePrefix:
type: string
maxLength: 200
enabled:
type: boolean
rpmLimit:
type: integer
minimum: 1
maximum: 10000
monthlyQuota:
type: integer
minimum: 1
maximum: 10000000
GatewayAPIKeyRequest:
type: object
required:
- name
properties:
name:
type: string
maxLength: 100
plan:
type: string
enum: [free, pro, business, enterprise]
default: free
enabled:
type: boolean
rpmLimit:
type: integer
minimum: 1
maximum: 10000
monthlyQuota:
type: integer
minimum: 1
maximum: 10000000
GatewayAPIKey:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
plan:
type: string
enabled:
type: boolean
rpm_limit:
type: integer
monthly_quota:
type: integer
key_prefix:
type: string
created_at:
type: string
format: date-time
GatewayResponse:
type: object
description: Standard gateway management envelope — `data` carries the payload, `error` carries {code, message, details}, `meta` carries pagination.
properties:
success:
type: boolean
data:
description: Endpoint-specific payload (GatewayService, GatewayAPIKey, arrays, or analytics objects)
error:
type: object
properties:
code:
type: string
message:
type: string
details: {}
meta:
type: object
properties:
page:
type: integer
per_page:
type: integer
total:
type: integer
total_pages:
type: integer
parameters:
IdParam:
name: id
in: path
required: true
description: Resource ID
schema:
type: string
ProjectIdParam:
name: id
in: path
required: true
description: Project ID
schema:
type: string
ServiceIdParam:
name: serviceId
in: path
required: true
description: Service ID
schema:
type: string
AgentIdParam:
name: id
in: path
required: true
description: Node agent ID
schema:
type: string
ContainerIdParam:
name: containerId
in: path
required: true
description: Container ID
schema:
type: string
tags:
- name: Health
description: Health check endpoints
- name: Authentication
description: User authentication and authorization
- name: User
description: User profile management
- name: Projects
description: Project management
- name: Services
description: Service management
- name: Deployments
description: Deployment lifecycle management
- name: Logs
description: Service and deployment log retrieval
- name: Builds
description: Build management
- name: Templates
description: Service template catalog and deployment
- name: Audit
description: Audit event history and resource-level trails
- name: Notifications
description: Persistent user notifications with read state
- name: Databases
description: Database management
- name: Git
description: Git integration
- name: System
description: System upgrade and host monitoring
- name: Realtime
description: WebSocket event stream
- name: Agents
description: Node agent management and agent ingestion
- name: Scaling
description: Autoscaling policies and controls
- name: HA
description: High availability, failover, health checks, alerts
- name: Preview Environments
description: Per-branch/PR preview deployments
- name: Security
description: Vulnerability scans and compliance reporting
- name: Cron
description: Scheduled jobs
- name: Registries
description: Private-image pull credentials
- name: BackupTargets
description: S3-compatible backup destinations for managed databases
- name: Gateway
description: API gateway — upstream services, keys, analytics