Skip to content

Automation API

The Automation API (/api/automation/v1/) lets external systems run operations on your servers. Call it from GitHub Actions, GitLab CI, Jenkins, or any system that can make HTTP requests.

For a setup guide with GitHub Actions, see GitHub Actions Integration.

Every request carries an automation key in the Authorization header:

Authorization: Bearer rca_your_key_here

Create keys in the dashboard. Open API Keys, select the Automation Keys tab, then click Create Key. Each key holds a list of operations and a scope of servers, registry credentials, and secret projects.

For the difference between API keys and automation keys, see API Overview. For the secret and target identifier each integration method uses, see the Credentials reference.

Every endpoint outside the catalog returns 403:

{
"detail": "Automation keys cannot use this endpoint."
}

A key that lacks the operation for a covered route gets a 403 that names the operation to add:

{
"detail": "This automation key does not have the `server:exec` operation (Run shell commands). Add the operation to the key, then try again."
}

Two routes stay open to every valid key, whatever its operations:

RouteWhy
GET /api/automation/v1/operations/{operation_id}Poll a job this key started. /exec and /deploy return a job id to poll.
GET /tenants/{tenant_id}/completion-indexShell completion data for the CLI. It returns the servers slice only to an automation key.
OperationRoutes
application:deployPOST /api/automation/v1/deploy
deploy_session:openPOST /external-deploy/session, DELETE /external-deploy/session/{session_id}, POST /external-deploy/sync, GET /external-deploy/status
container:restartPOST /api/automation/v1/restart
server:execPOST /api/automation/v1/exec
server:terminalWEBSOCKET /api/automation/v1/ws/terminal/{server_id}, WEBSOCKET /mcp/ws/terminal/{server_id}, WEBSOCKET /ws/terminal/{server_id}
server:rebootPOST /api/automation/v1/reboot
secret_session:openPOST /api/automation/v1/secrets/open-session, POST /api/automation/v1/secrets/resolve, GET /api/automation/v1/secrets/accessible-projects
registry:loginPOST /api/automation/v1/registry-auth/login, POST /api/automation/v1/registry-auth/login-direct
registry:logoutPOST /api/automation/v1/registry-auth/logout

Operation ids read as resource:verb. Keys created before this change hold flat names such as deploy and exec. Reoclo accepts those names as aliases, so existing keys keep working.

Old nameCanonical operation
deployapplication:deploy
restartcontainer:restart
execserver:exec
rebootserver:reboot
terminalserver:terminal
registry_loginregistry:login
registry_logoutregistry:logout
external_deploydeploy_session:open
POST /api/automation/v1/exec

Operation: server:exec.

Run a shell command on a server through the runner.

Request:

{
"server_id": "uuid",
"command": "docker compose up -d",
"working_directory": "/srv/reoclo/myapp",
"env": {
"DB_URL": "postgres://...",
"API_KEY": "secret"
},
"timeout_seconds": 300,
"run_id": "github-run-12345",
"run_context": {
"provider": "github_actions",
"repository": "myorg/myapp",
"workflow": "deploy",
"trigger": "push",
"actor": "username",
"sha": "abc123",
"ref": "refs/heads/main"
}
}
FieldRequiredDefaultDescription
server_idYes-Target server ID
commandYes-Shell command (max 8,192 chars)
working_directoryNo-Working directory on the server
envNo-Environment variables (max 200 keys, 64KB total)
timeout_secondsNo60Max execution time (1-900 seconds)
run_idNo-Groups related operations, such as a GitHub run ID
run_contextNo-CI metadata for audit trail

Response (completed):

{
"operation_id": "uuid",
"status": "completed",
"exit_code": 0,
"stdout": "...",
"stderr": "",
"duration_ms": 4500
}

Response (still running):

{
"operation_id": "uuid",
"status": "running"
}

If the command finishes within timeout_seconds, the response carries the full result. Otherwise, poll the operation status endpoint.

POST /api/automation/v1/deploy

Operation: application:deploy.

Trigger a deployment for an application.

Request:

{
"application_id": "uuid",
"commit_ref": "main",
"env_overrides": {
"FEATURE_FLAG": "true"
},
"run_id": "github-run-12345",
"run_context": { ... }
}
FieldRequiredDefaultDescription
application_idYes-Application to deploy
commit_refNoApp’s deploy branchBranch, tag, or SHA
env_overridesNo-Ephemeral env vars for this deployment only (not saved)
timeout_secondsNo60Max wait time
run_idNo-Groups related operations
run_contextNo-CI metadata

Response:

{
"operation_id": "uuid",
"status": "running",
"deployment_id": "uuid"
}

Deployments are always async. Poll the operation status for completion.

POST /api/automation/v1/restart

Operation: container:restart.

Restart the containers of an application.

Request:

{
"server_id": "uuid",
"container_name": "myapp",
"run_id": "github-run-12345"
}
POST /api/automation/v1/reboot

Operation: server:reboot.

Reboot a server. Reoclo uses the cloud provider API when one is available, and falls back to the runner.

Request:

{
"server_id": "uuid",
"run_id": "github-run-12345"
}
POST /api/automation/v1/registry-auth/login

Operation: registry:login.

Sign in to a container registry on the target server, using a registry credential stored in your Reoclo tenant. This endpoint is asynchronous. It creates an operation record and returns 202 immediately. Poll the operation status endpoint to track progress.

The API never returns the plaintext registry password. The response body carries the resolved registry URL and the registry provider type only.

Request:

{
"server_id": "uuid",
"credential_id": "uuid",
"run_id": "github-run-12345",
"run_context": { "provider": "github_actions", "repository": "myorg/myapp", "...": "..." }
}
FieldRequiredDescription
server_idYesTarget server ID (the runner must be connected)
credential_idYesRegistry credential UUID. Must be in the key’s allowed_credential_ids if scoped.
run_idNoGroups related operations
run_contextNoCI metadata for audit trail

Response (202 Accepted):

{
"operation_id": "uuid",
"status": "running",
"registry_url": "ghcr.io",
"registry_type": "ghcr"
}

Poll /operations/{operation_id} for the final result. The completed operation carries the exit_code, the captured stdout, the captured stderr, and duration_ms. Reoclo records the login and any later logout in the audit log.

POST /api/automation/v1/registry-auth/logout

Operation: registry:logout.

Run docker logout on the target server. This is the paired cleanup for registry-auth/login, which a GitHub Action post-step usually calls. Synchronous.

Request:

{
"server_id": "uuid",
"registry_url": "ghcr.io",
"run_id": "github-run-12345"
}

Response:

{
"operation_id": "uuid",
"status": "completed"
}

A logout failure does not return HTTP 5xx. It returns a completed operation with a non-zero exit code. Log those as warnings rather than errors.

POST /api/automation/v1/secrets/open-session
POST /api/automation/v1/secrets/resolve
GET /api/automation/v1/secrets/accessible-projects

Operation: secret_session:open.

These endpoints open a short-lived, read-only secret session for one CI run. The session reads only the secret projects granted to the key. An automation key can never create, change, roll back, or delete a secret.

Most pipelines call reoclo run instead of these endpoints. See Secrets in CI.

GET /api/automation/v1/operations/{operation_id}

Check the status of a running operation. Every valid key can call this route, whatever its operations.

Response:

{
"operation_id": "uuid",
"operation_type": "exec",
"server_id": "uuid",
"server_name": "prod-1",
"status": "completed",
"result": {
"exit_code": 0,
"stdout": "...",
"stderr": "",
"duration_ms": 4500
},
"run_id": "github-run-12345",
"started_at": "2026-04-10T14:30:00Z",
"completed_at": "2026-04-10T14:30:04Z"
}

Status values: running, completed, failed, timeout

GET /tenants/{tenant_id}/automation-keys/catalog

List every operation a key can hold, plus the presets. The dashboard renders the create and edit forms from this response.

This route sits outside /api/automation/v1/. Call it with a user session, not with an automation key. The caller needs the manager role or higher.

Response:

{
"operations": [
{
"id": "server:exec",
"label": "Run shell commands",
"description": "Run a shell command on a server.",
"group": "servers",
"group_label": "Servers",
"risk": "critical",
"server_scoped": true,
"note": "A key with this operation can do anything the runner user can do.",
"legacy_aliases": ["exec"]
}
],
"presets": [
{
"id": "github_actions_deploy",
"label": "Deploy from GitHub Actions",
"description": "Reoclo builds and runs the containers. The usual choice.",
"operations": [
"application:deploy",
"container:restart",
"registry:login",
"registry:logout"
]
}
]
}

Each entry in operations carries:

FieldDescription
idCanonical resource:verb operation id. Store this one on the key.
labelShort name the dashboard shows.
descriptionOne sentence on what the operation does.
groupGroup id: deployments, containers, servers, secrets, or registry.
group_labelDisplay name of the group.
riskstandard, elevated, or critical.
server_scopedWhether the key’s server allowlist narrows this operation.
noteExtra detail the dashboard shows under the description. Can be null.
legacy_aliasesOld flat names that still resolve to this operation.

Each entry in presets carries an id, a label, a description, and the operations it selects.

Each automation key carries these limits:

SettingDescription
OperationsWhich routes the key can call. An empty list allows nothing.
ServersWhich servers the key can target. Empty = all servers.
Registry credentialsWhich registry credentials the key can pass to registry-auth/login. Empty = all credentials in the tenant. Reoclo rejects cross-tenant references at create and update time.
Secret projectsWhich secret projects a secret session can read. Grant each project on its Access tab.
IP allowlistRestrict to specific IPs or CIDR ranges, such as GitHub runner IPs. Empty = allow all.
Rate limitRequests each minute (default: 100, max: 1000).
ExpirationOptional expiry date for the key.

Editing the expiry date of an existing key now works. Earlier versions reported success and changed nothing.

Each key carries a rate limit, 100 requests each minute by default. When a key exceeds that limit:

  • The API returns HTTP 429 Too Many Requests.
  • The Retry-After header gives the time to retry.
  • Reoclo logs the rate limit event in the audit trail.

Environment variables that you send in env (for exec) or env_overrides (for deploy) behave as follows:

  • The runner injects them into the command environment on the server.
  • Reoclo never stores them in its database.
  • Audit logs hold the key names only. Reoclo redacts the values.
  • The payload holds at most 200 keys and 64KB.

Reoclo logs every operation with:

  • The command that ran
  • The server it ran on
  • Exit code, stdout, stderr
  • The API key that made the call
  • CI context: repository, workflow, actor, commit SHA

Reoclo groups operations from the same CI run by run_id. Click the operation count on any automation key row to read its operation history in Logs.

CodeMeaning
401Invalid, revoked, or expired API key
403Endpoint not covered by any operation, operation not on the key, server not in scope, or IP not in the allowlist
404Server or application not found
422Validation error, such as an env payload too large or an invalid timeout
429Rate limit exceeded

All errors return:

{
"detail": "Human-readable error message"
}