Documentation Index
Fetch the complete documentation index at: https://docs.stacyide.xyz/llms.txt
Use this file to discover all available pages before exploring further.
StacyVM REST API Reference
This document is the source of truth for the StacyVM HTTP API. The Python and TypeScript SDKs are thin wrappers over these endpoints — anything they do, you can do withcurl.
- Base URL:
http://localhost:7423/api/v1 - Content type:
application/json(request and response, except where noted) - OpenAPI spec: swagger.yaml / swagger.json
Table of contents
- Authentication
- Conventions
- Errors
- Admin API
- Sandboxes
- Files
- Templates
- Providers
- Workers
- Snapshots
- Pool
- System
- Events stream
- WebSocket exec
Authentication
Optional headers:| Header | Purpose | Required when |
|---|---|---|
X-API-Key | API key authentication | auth.enabled: true in stacyvm.yaml |
X-Admin-API-Key | Admin API key authentication | auth.admin_api_key is configured and calling /api/v1/admin/* |
X-User-ID | Multi-tenant pool mode user identifier | pool.enabled: true |
server.cors_allowed_origins: ["*"]). Public deployments should set exact origins, for example:
stacyvm config lint --production fails when CORS is left wildcard or empty.
X-User-ID is trimmed when present. It must be 128 characters or fewer and cannot contain whitespace, control characters, or path separators.
Rate limiting
API rate limiting is optional and disabled by default. Whenrate_limit.enabled is true, StacyVM applies an in-memory token bucket to API routes.
owner mode uses X-User-ID when present, then falls back to X-API-Key, then client IP. Limited requests return 429 Too Many Requests with Retry-After, X-RateLimit-Limit, and X-RateLimit-Remaining headers.
Rate-limit buckets store hashed identity keys internally; raw owner IDs, API keys, and IP addresses are not exposed in diagnostics or metrics.
Conventions
- IDs. Sandbox IDs look like
sb-a1b2c3d4. Templates are addressed byname. - Durations. All
ttlandtimeoutfields use Go duration strings:30s,5m,1h30m. - Timestamps. ISO 8601 UTC, e.g.
2026-05-04T10:30:00Z. - File modes. Octal strings, e.g.
"755","644". - Streaming.
POST /sandboxes/{id}/execswitches to NDJSON (application/x-ndjson) whenstream: true.
Errors
Errors return a JSON body with HTTP status reflecting the failure class:| Status | Code | When |
|---|---|---|
400 | bad_request | Invalid input — missing field, malformed JSON |
401 | unauthorized | Bad / missing API key |
404 | not_found | Sandbox / template / provider does not exist |
409 | conflict | Template name already exists |
429 | resource_limit | Quota, capacity, or API rate limit exceeded |
500 | provider_error | Provider failed (Docker, Firecracker, etc.) |
503 | unavailable | Pool full with overflow: reject |
Admin API
StacyVM supports an optional separate admin API key:X-Admin-API-Key for admin requests. X-API-Key is still accepted when it matches the admin key. If auth.admin_api_key is empty, admin routes fall back to auth.api_key for backwards compatibility unless auth.admin_fallback_enabled is set to false.
For dashboard setup, quota workflows, diagnostics, audit history, CSV export, and storage notes, see admin-control-plane.
Admin route aliases:
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/admin/providers | List providers with health details |
GET | /api/v1/admin/providers/{name} | Provider detail |
POST | /api/v1/admin/providers/test | Run provider health checks |
GET | /api/v1/admin/quotas | List owner quota overrides |
GET | /api/v1/admin/quotas/summary | Redacted quota coverage summary |
GET | /api/v1/admin/quotas/{ownerID} | Get owner quota |
PUT | /api/v1/admin/quotas/{ownerID} | Create or update owner quota |
GET | /api/v1/admin/quotas/{ownerID}/usage | Owner usage against effective quota |
DELETE | /api/v1/admin/quotas/{ownerID} | Delete owner quota |
GET | /api/v1/admin/diagnostics | Redacted operational diagnostics |
GET | /api/v1/admin/metrics | Structured JSON metrics |
GET | /api/v1/admin/metrics/prometheus | Prometheus metrics |
GET | /api/v1/admin/audit | Filterable admin audit history, with optional format=csv |
Sandboxes
Spawn a sandbox
201 Created:
Evaluate spawn admission
X-User-ID overrides owner_id, matching the spawn endpoint.
Request body: same shape as POST /api/v1/sandboxes.
Response 200 OK:
queueable reflects the configured spawn overflow mode. Capacity denials are queueable only when defaults.spawn_overflow is queue; TTL denials are never queueable.
List sandboxes
200 OK: array of sandbox objects.
Get a sandbox
200 OK or 404 Not Found.
Destroy a sandbox
200 OK:
Prune expired sandboxes
200 OK:
Extend TTL
200 OK: full sandbox object with updated expires_at.
Execute a command
200 OK (non-streaming):
200 OK (streaming, stream: true): application/x-ndjson — one JSON object per line:
Console logs
lines defaults to 100.
Response 200 OK:
Files
All file paths are absolute inside the sandbox. The endpoints below are scoped under/sandboxes/{id}/files.
Write a file
200 OK: { "status": "written" }.
Read a file
200 OK: raw file contents (binary safe). The SDKs decode as UTF-8.
Delete a file or directory
recursive defaults to false. Response 200 OK: { "status": "deleted" }.
List a directory
path defaults to /.
Response 200 OK:
Move / rename
200 OK: { "status": "moved" }.
Change permissions
200 OK: { "status": "chmod applied" }.
Stat
200 OK: a single FileInfo object (same shape as list).
Glob
200 OK:
Templates
Create a template
201 Created: the template object. 409 Conflict if name is taken.
List templates
200 OK: array of templates.
Get a template
200 OK or 404 Not Found.
Update a template
name). Response 200 OK or 404.
Delete a template
200 OK: { "status": "deleted" }.
Spawn from a template
201 Created: full sandbox object.
Quotas
Owner quotas are persisted overrides for per-owner sandbox and runtime limits. They apply when requests include an owner viaX-User-ID or owner_id.
Owner IDs are trimmed and must be 128 characters or fewer. They cannot contain whitespace, control characters, or path separators. Quota durations must use whole-second Go duration strings; use 0s or omit a duration to inherit the global default.
List owner quotas
200 OK:
Get quota summary
200 OK:
Save owner quota
200 OK: full owner quota object.
Invalid owner IDs, negative sandbox counts, malformed durations, sub-second durations, and fractional-second durations return 400 Bad Request.
Get owner usage
200 OK:
Delete owner quota
200 OK: { "status": "deleted" }.
Providers
List providers
200 OK:
Get a provider
200 OK:
Health-check all providers
200 OK:
Workers
Worker registry endpoints expose the control-plane view of StacyVM workers. In single-node mode the API server registers itself as thelocal worker at startup. Remote workers heartbeat through /api/v1/worker/* using worker credentials. Admins can still manage registry records under /api/v1/admin/workers/*.
List workers
200 OK:
Get a worker
200 OK: one worker object.
Heartbeat a worker
200 OK: updated worker object.
Admin heartbeat aliases remain available at /api/v1/admin/workers/{workerID}/heartbeat for controlled registry repair and test setup.
Renew a worker lease
auth.worker_token is the shared staging token. For production-aligned worker identity, configure auth.worker_signing_key for short-lived signed worker tokens or auth.worker_tokens.<workerID> for individually rotatable static credentials during migration.
Request:
200 OK:
Delete a worker
200 OK:
Snapshots
List Firecracker snapshots
200 OK: array of snapshot summaries (image name, kernel, size, created_at).
Pool
Pool status
200 OK (pool enabled):
200 OK (pool disabled):
System
Health
200 OK:
Liveness
200 OK:
Readiness
200 OK:
503 Service Unavailable when no configured provider is healthy.
Diagnostics
200 OK:
remediation object points operators to the first public document to use when a diagnostics area needs follow-up.
Metrics
200 OK:
Prometheus metrics
200 OK:
Events stream
200 OK with Content-Type: text/event-stream. The server emits orchestrator events as Server-Sent Events:
sandbox.created,sandbox.running,sandbox.destroyed,sandbox.errorexec.started,exec.completed,exec.failed,exec.timeoutfile.written,file.readoperation.failed,resource.limit,provider.failed,reconcile.actionspawn.queued,spawn.dequeued,spawn.queue_timeoutquota.saved,quota.deleted
EventSource in browsers, httpx-sse in Python, etc.) to consume.
WebSocket exec
web/src/.
SDK mapping
If you’d rather write Python or TypeScript thancurl, every endpoint above maps 1:1 to an SDK method:
| Endpoint | Python | TypeScript |
|---|---|---|
POST /sandboxes | client.spawn(...) | client.spawn(...) |
GET /sandboxes/{id} | client.get(id) | client.get(id) |
POST /sandboxes/{id}/exec | sb.exec(cmd) / sb.exec_stream(cmd) | sb.exec(cmd) / sb.execStream(cmd) |
POST /sandboxes/{id}/files | sb.write_file(path, content) | sb.writeFile(path, content) |
GET /sandboxes/{id}/files | sb.read_file(path) | sb.readFile(path) |
POST /templates/{name}/spawn | client.spawn_template(name) | client.templates.spawn(name) |
GET /pool/status | client.pool_status() | client.poolStatus() |
GET /health | client.health() | client.health() |

