Skip to content

API reference

Everything the panel UI does goes through the same REST API the backend exposes at /api/*. You can drive Mezzanine programmatically with it.

Conventions

  • Base URLhttps://app.yourdomain.com/api
  • Auth — an HTTP-only cp_session cookie set by POST /api/auth/login. All routes except /api/auth/* and /api/webhooks/* require it.
  • Roles — non-GET requests need at least moderator; destructive routes need admin. A 403 INSUFFICIENT_ROLE body tells you what’s missing.
  • Responses — JSON. Mutations return { ok: true, ... }; errors return { error: "message" } with an appropriate status.
  • WebhooksPOST /api/webhooks/:workflowId is public but HMAC-SHA256 verified against the workflow’s secret.

Auth

MethodPathPurpose
GET/api/auth/state{ needs_setup, authenticated, user }
POST/api/auth/setupCreate the first admin (only when needs_setup)
POST/api/auth/login{ username, password, totp? } → sets session cookie
POST/api/auth/logoutRevoke the current session
POST/api/auth/change-password{ current, next }

Servers

MethodPathPurpose
GET/api/serversList adopted servers
POST/api/serversAdopt a server { name, host, port, username, auth_type, password? / private_key? }
GET/api/servers/:idServer detail + live status
PATCH/api/servers/:idUpdate connection / tags
DELETE/api/servers/:idRemove
GET/api/servers/:id/deploy-keyGet/generate the server’s ed25519 deploy key

Deploy workflows

MethodPathPurpose
GET/api/workflowsList workflows
POST/api/workflowsCreate { name, server_id, definition }
GET/api/workflows/:idWorkflow + recent runs
POST/api/workflows/:id/runTrigger a manual run → { runId }
POST/api/workflows/:id/webhook/rotateMint a new webhook URL + HMAC secret
GET/api/deployments/runs/:runIdRun status + per-step output

Pools

MethodPathPurpose
GET/api/poolsList pools (+ member counts)
POST/api/poolsCreate { name, workflow_id?, domain_id?, min_replicas?, max_replicas? }
GET/api/pools/:idPool + members
PATCH/api/pools/:idUpdate (incl. LB: edge_server_id, lb_strategy, ports)
POST/api/pools/:id/scale-out{ server_id } → add member + deploy
POST/api/pools/:id/sync-lbRe-render + reload the nginx upstream
DELETE/api/pools/:id/members/:serverIdRemove a member

Providers

MethodPathPurpose
GET/PUT/DELETE/api/hostinger/*Hostinger VPSes, domains, DNS, email, billing
GET/POST/PATCH/DELETE/api/contabo/*Contabo instances, snapshots, secrets, usage
GET/POST/api/digitalocean/*Droplets + DNS
GET/POST/PATCH/DELETE/api/cloudflare/zones/:id/dnsDNS records
GET/POST/DELETE/api/cloudflare/zones/:id/email/*Email Routing — rules, destinations, catch-all

Docker (per server)

MethodPathPurpose
GET/api/servers/:id/docker/containersList containers
POST/api/servers/:id/docker/containers/:cid/:actionstart / stop / restart / remove
GET/api/servers/:id/docker/imagesList images + update checks

Example: trigger a deploy from CI

Terminal window
# Manual trigger with a session cookie
curl -X POST https://app.yourdomain.com/api/workflows/$WF_ID/run \
-H 'Content-Type: application/json' \
--cookie "cp_session=$SESSION"
# Or fire the HMAC-signed webhook (no session needed)
BODY='{"ref":"refs/heads/main"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
curl -X POST https://app.yourdomain.com/api/webhooks/$WF_ID \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: sha256=$SIG" \
-d "$BODY"

Notes

This reference covers the most-used route groups, not every endpoint. The authoritative list is the route files in backend/src/routes/ — each maps 1:1 to a /api/<resource> prefix. A generated OpenAPI spec is on the roadmap.