Skip to content
View as Markdown

REST API ​

Base URL is whatever you run the control plane at. Every endpoint below talks JSON, and every one is reachable from a script, an SDK, or curl.

Authentication ​

Two headers are accepted, and they mean different things:

HeaderCredentialScope
X-Sandrpod-Tokenplatform tokeneverything, every workspace
X-Sandrpod-Tokensk_… workspace keyone workspace
X-Sandrpod-Tokene2b_… E2B keyone workspace (the E2B spelling of the same key)
Cookie: sandrpod_sessionbrowser sessionthe signed-in workspace

The platform token is the operator credential: it can list every sandbox and delete every worker. Do not ship it inside an agent.

Sandboxes ​

MethodPathNotes
POST/api/v1/sandboxescreate. async:true returns 202 with a job id
GET/api/v1/sandboxeslist, scoped by credential
GET/api/v1/sandboxes/{name}one sandbox
DELETE/api/v1/sandboxes/{name}delete record and container
POST/api/v1/sandboxes/{name}/start | /stopresume / pause
POST/api/v1/sandboxes/execute?sandbox={name}run code
GET/api/v1/sandboxes/stream?sandbox={name}streaming run
GET/api/v1/sandboxes/{name}/toolbox/*proxy to the in-sandbox toolbox
POST/api/v1/sandboxes/{name}/snapshotcommit the container to an image

Create body:

json
{
  "name": "agent-01",
  "provider_type": "local",
  "region": "local",
  "cpu_cores": 1,
  "memory_mb": 1024,
  "ttl_seconds": 3600,
  "network": { "allowed_domains": ["pypi.org", "github.com"] }
}

A network policy on a fleet with no egress-capable worker answers 409 rather than starting an unenforced sandbox.

Execution ​

bash
curl -s -X POST "$API/api/v1/sandboxes/execute?sandbox=agent-01" \
  -H "X-Sandrpod-Token: $TOKEN" -H 'Content-Type: application/json' \
  -d '{"language":"bash","code":"echo hi","timeout":20}'
json
{"exit_code":0,"stdout":"hi\n","stderr":"","started_at":"…","ended_at":"…"}

language is bash, python, node, or sh. timeout is seconds.

Workers ​

MethodPathNotes
GET/api/v1/podersinventory with state, resources, capabilities, region
DELETE/api/v1/poders/{id}remove a record (and its tunnel)
POST/api/v1/poders/{id}/heartbeatworkers only; a worker may heartbeat itself and nothing else
GET/ws/poder/connectthe WebSocket a worker dials (not called by hand)

Egress ​

MethodPathNotes
GET/api/v1/sandboxes/{name}/egresscurrent policy, null when unset
PUT/api/v1/sandboxes/{name}/egressreplace it (validated)
DELETE/api/v1/sandboxes/{name}/egressunset it — not the same as PUT {}
POST/api/v1/policy/decideper-connection verdict, for -egress-mode=decider

Operations ​

MethodPathNotes
GET/healthliveness and version
GET/healthzthe deeper check: database, workers, payments, disk
GET/metricsPrometheus; needs an admin credential
GET/api/v1/capabilitieswhat this control plane supports (egress_policy, …)

Errors ​

StatusMeaning
400malformed body or an invalid name
401no or unknown credential
403valid credential, not allowed (a worker reaching the fleet view, a member spending)
404no such sandbox
409conflict: name taken, sandbox not RUNNING, or a capability no worker has
429rate limited; Retry-After says how long
503the worker that owns the sandbox is not connected to any instance

E2B-compatible surface ​

A second, E2B-shaped surface can be mounted on its own domain. It is documented in E2B drop-in; the paths are /sandboxes, /sandboxes/{id}, /sandboxes/{id}/pause, and envd RPCs on <port>-<id>.<domain>.

OpenAPI ​

The control plane serves its OpenAPI document at /api/v1/openapi.json on builds that include it; the E2B surface's schema is E2B's own (spec/openapi.yml upstream), which is what makes a drop-in possible.

Apache 2.0 — your clouds, your machines, your rules.