Instances API
The /api/v1 instances surface — list, CRUD, lifecycle, limits, readiness, console, snapshots.
Everything the panel does is available on the API. The web UI and any mobile client all call the same procedures. This page documents the instances surface. Each procedure requires a permission, and the server enforces it — the access rules below are real, not just documentation.
Transport
Procedures are reached over oRPC at /api/rpc/* (typed client) and exposed on /api/v1 (OpenAPI).
Inputs/outputs below are the wire shapes; the agent-facing protocol types they map to live in
@spipcp/protocol.
Permissions
| Permission | Grants |
|---|---|
instances:view | List, get, drift, runs, readiness, metrics. Held by operators. |
instances:create | Create an instance. |
instances:manage | Edit limits, start/stop/restart. |
instances:remove | Delete an instance. |
instances:reconcile | Trigger a reconcile / dry-run drift check. Held by operators. |
instances:console | Open a console PTY session. Admin-only, audited. |
instances:snapshot | Create / restore / delete snapshots. Admin-only. |
Operators hold only instances:view + instances:reconcile. Every other instance procedure returns
403 for an operator.
Read
instances.list
instances:view — { nodeId?: string } → InstanceSummary[]. All instances newest-first, optionally
scoped to one node.
instances.get
instances:view — { id } → InstanceSummary & { drift }. One instance with its latest drift state.
404 if unknown.
instances.drift
instances:view — { id } → DriftState | null.
instances.runs
instances:view — { id, limit?, offset? } → ReconcileRun[]. Reconcile-run history (newest-first).
InstanceSummary fields: id, nodeId, name, image, type, status, cpuLimit, memLimitMb, diskGb, configVersion, createdAt, updatedAt. status is one of pending | creating | running | stopped | error.
Create & limits
instances.create
instances:create —
{ nodeId, name, image, type?: "container" | "vm",
cpuLimit?: 1..64, memLimitMb?: 128..262144, diskGb?: 1..4096 }
→ { instance: InstanceSummary, runId }Records the instance (status pending) and starts the first reconcile; the agent builds the real
Incus container. name must be a valid Incus name (^[a-z][a-z0-9-]*$). 404 if the node is unknown.
instances.updateLimits
instances:manage — { id, cpuLimit, memLimitMb, diskGb } → { instance, runId }. Applies new CPU,
memory, and disk limits live.
Lifecycle
instances.lifecycle
instances:manage — { id, action: "start" | "stop" | "restart" } → { queued: true }. Starts, stops,
or restarts the instance. Audited as instance.<action>.
instances.remove
instances:remove — { id } → { removed: true }. Deletes the instance and tears the container down
on the node. Audited.
instances.triggerReconcile
instances:reconcile — { id, dryRun?: boolean } → { runId }. Triggers a reconcile, or a dry-run
drift check (no mutations). 404 if unknown.
Readiness
instances.readiness
instances:view — { id } → { ready: boolean, gates: Gate[] } where
Gate = { check: string, status: "pass" | "fail", code: string, detail: string, remedy?: string }The checks (NIC on bridge, DHCP lease, DNS, apt reachability) run inside the instance before any
service install; a failing check names its remedy. The instance isn't "ready" until all checks
pass.
Metrics
instances.metrics
instances:view — { id } → IncusInstanceMetricsResult:
{ name, status, privateIp?, cpuUsageNs, cpuAllocatedTimeNs?,
memoryUsedMb, memoryTotalMb, diskUsedGb, diskTotalGb,
networkRxBytesTotal, networkTxBytesTotal, uptimeSeconds?, sampledAt }A live sample read from the agent; it powers the workspace usage bars. Poll it for a moving view.
Console
instances.consoleSession
instances:console (admin-only, audited) — { id } → { ptyUrl }. Mints a short-lived,
single-use token and returns a fully-formed WebSocket URL of the form
ws(s)://<worker>/pty/instance/:instanceId?token=…. The client connects xterm.js to it for an
interactive incus exec PTY. Returns 403 for operators (and the UI hides the console tab).
Snapshots
instances:snapshot (admin-only) — all keyed by the snapshot name:
| Procedure | Input | Output |
|---|---|---|
instances.snapshot.list | { id } | IncusSnapshot[] ({ name, createdAt?, expiresAt?, stateful?, sizeBytes? }) |
instances.snapshot.create | { id, snapshotName } | { snapshotName } |
instances.snapshot.restore | { id, snapshotName } | { restored: true } |
instances.snapshot.delete | { id, snapshotName } | { deleted: true } |
Mobile-app ready
These are the same procedures the web workspace calls — a mobile client lists, creates, consoles, and snapshots through this same surface. There's no separate "mobile API".
Sites API
The /api/v1 sites surface — list, get, launch, resume, delete, env, cron/workers, stop/start, tag, and the live launch stream.
Domains & Routes API
The /api/v1 domains + routes surface — list, get, attach, renew, detach, the orange-cloud toggle, driver list, test-credentials, provider DNS accounts, the self-hosted nameserver/zone endpoints, and the http/raw route CRUD.