v0.2.4

REST API Reference

Base URL: http://<master>:6880

All endpoints except /api/v1/health and /api/v1/webhooks/github require a bearer token:

Authorization: Bearer <token>

Each route needs a permission. viewer holds status, logs and cluster_info; deployer adds deploy, stop, scale and rollback; admin holds everything. secrets and the routes marked admin are admin-only, and so is any route not listed here.

Endpoints

Health & Metrics

MethodPathPermissionDescription
GET/api/v1/healthnoneCluster health check
GET/metricsstatusPrometheus metrics

Services

MethodPathPermissionDescription
POST/api/v1/deploydeployDeploy services
GET/api/v1/status?project=statusService status
GET/api/v1/services/{name}/logslogsContainer logs (tail, follow)
GET/api/v1/services/{name}/execadminInteractive exec (WebSocket)
POST/api/v1/services/{name}/scalescaleScale replicas
POST/api/v1/services/{name}/startdeployStart (resume) a paused service
POST/api/v1/services/{name}/redeploydeployPull the image and recreate
POST/api/v1/services/{name}/promotedeployPromote canary
POST/api/v1/services/{name}/rollbackrollbackRollback deploy
DELETE/api/v1/services/{name}stopStop service
DELETE/api/v1/projects/{project}stopStop all in project
POST/api/v1/stopstopStop ALL services

Cluster

MethodPathPermissionDescription
GET/api/v1/cluster/infocluster_infoNode list and cluster info
POST/api/v1/cluster/nodes/{id}/drainadminDrain a node
POST/api/v1/cluster/nodes/{id}/undrainadminUndrain a node
GET/api/v1/cluster/networksstatusPer-node Docker networks and public routes
GET/api/v1/cluster/backupsstatusBackup status per node
POST/api/v1/cluster/backups/triggeradminTrigger a backup
GET/api/v1/ws/agentadmin tokenAgent channel (WebSocket, token in Authorization)

Cluster token rotation

MethodPathPermissionDescription
POST/api/v1/cluster/token/rotateadminStart a rotation
GET/api/v1/cluster/token/rotationadminRotation progress
POST/api/v1/cluster/token/rotation/finishadminRetire the old token

Secrets

MethodPathPermissionDescription
GET/api/v1/secretssecretsList keys (never values)
GET/api/v1/secrets/usagesecretsKeys with the services that reference them
POST/api/v1/secrets/{key}secretsCreate or update a secret
DELETE/api/v1/secrets/{key}secretsRemove a secret

Webhooks

MethodPathPermissionDescription
POST/api/v1/webhooks/githubsignatureGit push webhook
GET/api/v1/webhooksstatusList registered webhooks
POST/api/v1/webhooksadminRegister a webhook
DELETE/api/v1/webhooks/{id}adminRemove a webhook
GET/api/v1/webhooks/{id}/invocationsstatusRecent invocations

AI and alerts

MethodPathPermissionDescription
POST/api/v1/askstatusAsk the AI assistant
GET/api/v1/alertsstatusList alert conversations
GET/api/v1/alerts/{id}statusOne conversation
POST/api/v1/alerts/{id}/replyadminReply to the AI
POST/api/v1/alerts/{id}/dismissadminDismiss
POST/api/v1/alerts/{id}/resolveadminResolve

Deploy Payload

POST /api/v1/deploy
Content-Type: application/json

{
  "services": [{
    "name": "my-app",
    "project": "frontend",
    "image": "nginx:alpine",
    "replicas": 2,
    "port": 80,
    "domain": "app.example.com",
    "health": "/healthz",
    "env": {
      "KEY": "${secrets.KEY}"
    },
    "resources": {
      "memory": "512Mi",
      "cpu": 1.0
    },
    "internal": true,
    "placement": {
      "node": "worker-1"
    }
  }]
}

Response

{
  "deployed": ["my-app"],
  "errors": []
}
StatusMeaning
200Every service deployed
206Some services deployed, the rest are listed in errors
400Validation failed; nothing deployed
500No service deployed

Scale Payload

POST /api/v1/services/my-app/scale
Content-Type: application/json

{
  "replicas": 5
}

Log Query

GET /api/v1/services/my-app/logs?tail=100

Returns plaintext log output. tail defaults to 100; follow=true streams new lines for services on the master.

Status Response

GET /api/v1/status

{
  "services": [
    {
      "name": "my-app",
      "project": "frontend",
      "status": "running",
      "replicas": 2,
      "running_replicas": 2,
      "image": "nginx:alpine",
      "domain": "app.example.com"
    }
  ]
}

Token Rotation

POST /api/v1/cluster/token/rotate takes no body. POST /api/v1/cluster/token/rotation/finish takes an optional body:

{ "force": false }

All three routes return the rotation status. No response contains a token:

{
  "in_progress": true,
  "token_file": "/root/.orca/cluster.token",
  "nodes": [
    { "node_id": 7, "address": "10.0.0.7:6880", "rotated": true, "persisted": true, "detail": null }
  ]
}

rotated means the agent uses the new token now; persisted means its next start will too. detail says where it saved the token, or what must be fixed by hand. Starting a rotation while one runs, finishing when none runs, or finishing while an agent is not rotated and persisted (without force) returns 409 with the reason as plain text.

Webhook Verification

GitHub/Gitea webhooks are verified using HMAC-SHA256. The webhook secret is configured when registering the webhook via orca webhooks add. Registering a webhook without a secret returns 400, and pushes without a valid signature are rejected.

Error Responses

All errors return JSON:

{
  "error": "service not found: my-app"
}
StatusMeaning
401Missing or invalid token
403Insufficient role permissions
404Service or resource not found
409Token rotation refused (see above)
500Internal server error
503Target agent node is offline (webhook redeploy to disconnected node)