Base URL: /api/v1
All protected endpoints require one of:
- JWT Token:
Authorization: Bearer <token>(obtained from login) - API Key:
X-API-Key: <key>(generated in profile) - Master Key:
X-Master-Key: <key>(configured in server env)
Agent endpoints require:
- Agent Token:
X-Agent-Token: <token>(must match server'sAGENT_TOKEN)
Login with email and password. Note: the request field is named username
but holds the user's email address.
Request:
{
"username": "admin@example.com",
"password": "admin"
}Response (200):
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer"
}The JWT payload carries sub (user ID), email, name, role, and exp
(24h). There is no separate user object in the response and no refresh
token — decode the JWT client-side if you need those fields.
Public health check. Returns DB and Docker status.
Response (200):
{
"status": "healthy",
"checks": {
"database": "ok",
"docker": "ok"
}
}Status values: healthy, degraded (Docker down), unhealthy (DB down, returns 503).
Prometheus-format metrics endpoint (public).
Metrics exposed:
conman_http_requests_total{method, path, status}conman_http_request_duration_seconds{method, path}conman_agents_total{status}conman_containers_totalconman_report_ingest_totalconman_report_ingest_errors_totalconman_websocket_connections
List all registered agents.
Query Parameters:
tag-- Filter by tag (e.g.,?tag=production)runtime-- Filter by runtime type (e.g.,?runtime=containerd)
Response (200):
[
{
"id": "abc-123-...",
"name": "prod-host-01",
"host_info": {
"hostname": "prod-host-01",
"os": "Ubuntu 22.04",
"runtime_type": "docker",
"runtime_version": "26.0.0",
"cpus": 4,
"memory_total": 8589934592
},
"status": "healthy",
"runtime_type": "docker",
"last_heartbeat": "2026-04-08T10:00:00Z",
"containers": [...],
"images": [...]
}
]Get a specific agent with full state (containers, images, networks, volumes, metrics).
Remove an agent registration.
Update tags for an agent.
Request:
{
"tags": ["production", "us-east", "gpu"]
}List containers on a specific agent.
List images on a specific agent.
List networks on a specific agent.
List volumes on a specific agent.
WebSocket endpoint. Proxied interactive terminal to a container on a remote agent.
WebSocket endpoint. Proxied log streaming from a container on a remote agent.
WebSocket endpoint. Proxied real-time stats from a container on a remote agent.
Container lifecycle operations proxied to a remote agent.
Remove a container on a remote agent.
Pull an image on a remote agent.
Remove an image on a remote agent.
Get disk usage information from a remote agent.
List containers on the local Docker daemon.
Inspect a local container.
Container lifecycle operations.
Remove a local container.
WebSocket endpoint. Interactive terminal session.
WebSocket endpoint. Real-time log streaming.
WebSocket endpoint. Real-time CPU/memory/network stats.
List files inside a container.
Download a file from a container.
List all images.
Inspect an image.
Pull an image.
Request:
{
"image": "nginx:latest"
}Remove an image.
Check if an image has updates available.
Remove unused images.
List all networks.
Create a network.
Remove a network.
Duplicate a network configuration.
Connect a container to a network.
Disconnect a container from a network.
List all volumes.
Create a volume.
Remove a volume.
Remove unused volumes.
Browse volume contents.
List all stacks.
Create and deploy a stack.
Request:
{
"name": "my-stack",
"compose_content": "version: '3'\nservices:\n web:\n image: nginx",
"env_content": ""
}POST /stacks returns a webhook_secret field once, in this response only
— it is never included in GET /stacks, GET /stacks/{id}, or any other
read. Save it immediately; regenerate via POST /stacks/{id}/webhook-secret
if lost (invalidates the old one).
Stack names must match ^[a-z0-9][a-z0-9_-]{0,62}$ (used as a filesystem
directory component) — anything else is rejected with 400.
Get stack details.
Update a stack's compose configuration.
Stop all services in a stack.
Remove a stack and its services.
Trigger a redeploy from the authenticated dashboard. Requires the same
auth/RBAC/license gate as the rest of /stacks — no signature needed.
Regenerate this stack's webhook secret, invalidating the old one. Returns the
new secret once: {"webhook_secret": "..."}.
Public route — no JWT/API key/master key. For CI/CD pipelines. Requires
an X-Webhook-Signature: sha256=<hex> header: HMAC-SHA256 of the raw request
body, keyed with the stack's webhook_secret. Missing/malformed header, or a
signature that doesn't match → 401. A stack with no secret set (shouldn't
happen for anything created after webhook secrets were introduced) → 403.
SECRET="<webhook_secret from stack creation>"
BODY=""
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')
curl -X POST -H "X-Webhook-Signature: sha256=$SIG" \
https://your-server/api/v1/webhooks/stacks/1Query historical metrics for a container.
Query Parameters:
from-- Start time (RFC3339, e.g.,2026-04-08T00:00:00Z)to-- End time (RFC3339)limit-- Max results (default 1000)agent_id-- Filter by agent
Response (200):
[
{
"time": "2026-04-08T10:05:00Z",
"agent_id": "abc-123",
"container_id": "def-456",
"container_name": "nginx",
"cpu_percent": 2.5,
"memory_usage": 52428800,
"memory_percent": 1.2,
"network_rx": 1024000,
"network_tx": 512000,
"pids": 5
}
]Query historical metrics for all containers on an agent. Same query parameters as above.
List all alert rules.
Create an alert rule.
Request:
{
"name": "Agent Offline Alert",
"type": "agent_offline",
"config": "{\"timeout_minutes\": 5}",
"enabled": true
}Update an alert rule.
Delete an alert rule and its events.
List notification channels.
Create a notification channel.
Request:
{
"name": "Slack Alerts",
"type": "webhook",
"config": "{\"url\": \"https://hooks.slack.com/services/...\", \"headers\": {}}"
}Update a notification channel.
Delete a notification channel.
List fired alert events.
Query Parameters:
agent_id-- Filter by agentresolved-- Filter by resolution status (trueorfalse)
List all users. Requires admin role.
Create a user. Requires admin role.
Request:
{
"email": "operator@example.com",
"password": "secure-password",
"full_name": "Jane Ops",
"role": "operator"
}Roles: admin, operator, viewer
Update a user.
Requires the api license feature (Pro+Enterprise) — Community gets
403 {"license_required":true,"feature":"api"} on all three routes.
List your API keys. Each entry has a key_prefix (first 11 chars) for
display — the full key is never returned here.
Generate a new API key.
Request:
{
"name": "ci-pipeline",
"expires_in_days": 90
}expires_in_days is optional (0 or omitted = never expires). The response
includes the full key exactly once — it is not recoverable after this call.
Revoke (permanently delete) an API key. Scoped to your own keys only.
Requires the audit_logs license feature (Enterprise only) — Pro/Community
get 403 {"license_required":true,"feature":"audit_logs"} on both routes.
List system activity events (container lifecycle, OOM kills, user actions).
Aggregate activity counts.
Docker daemon information.
Docker disk usage.
System resource usage (CPU, memory, disk).
Remove stopped containers.
All errors return JSON:
{
"error": "Description of the error"
}Common status codes:
400-- Bad request (invalid input)401-- Unauthorized (missing or invalid token)403-- Forbidden (insufficient permissions)404-- Not found429-- Rate limited500-- Internal server error502-- Bad gateway (agent unreachable)503-- Service unavailable (health check failed)