Sandboxes
Core CRUD and lookup for sandbox microVMs.
At a glance
- Base URL:
https://api.sb.createos.sh - Auth:
X-Api-Key: <token>header — get a token - Response envelope: JSend —
{"status": "...", "data": ...}
Sandbox status lifecycle
A sandbox moves through these statuses:
| Status | Description |
|---|---|
creating | Spawn in progress |
running | Active; can exec and transfer files |
pausing | Snapshot in progress |
paused | Snapshotted to storage; host freed |
resuming | Restoring from snapshot |
forking | Bundle copy in progress (source stays paused) |
error | Resume/fork exhausted retries; POST /resume to retry |
destroying | Delete in progress |
destroyed | Permanently gone |
failed | Terminal failure |
POST /v1/sandboxes
Create a new sandbox. Typical startup is 30–100 ms.
Auth required: Yes
Request body
| Field | Type | Required | Description |
|---|---|---|---|
shape | string | Yes | VM shape. See GET /v1/shapes for the catalog. Example: s-1vcpu-256mb |
rootfs | string | No | Rootfs catalog name. Omit for host default. See GET /v1/rootfs. Disabled names are rejected with 400. |
name | string | No | User-facing VM name, unique per user among non-terminal sandboxes. Auto-generated (<adjective>-<animal>) if omitted. Used as hostname and in-network DNS name. |
disk_mib | integer | No | Disk size in MiB. 0 = shape default (10 GiB). |
ssh_pubkeys | string[] | No | OpenSSH public keys for SSH gateway access. Required for fcctl tunnel / fcctl shell. |
envs | object | No | Environment variables exported into every exec. Keys must match ^[A-Za-z_][A-Za-z0-9_]*$. Up to 64 entries, 4 KiB per value, 64 KiB total. Values are never returned by GET — only key names. |
ingress_enabled | boolean | No | When true, sandbox is reachable at <ulid>-<port>.<domain>. Off by default. |
networks | object[] | No | Private networks to join at create time. Each entry: {"id": "<name|net-ulid>"}. |
disks | object[] | No | S3 disks to mount. Each entry: {"disk_id": "<name|id>", "mount_path": "/mnt/data", "sub_path": "optional/prefix"}. Disk must be pre-registered via POST /v1/disks. |
egress | string[] | No | Outbound allowlist. Each entry is host[:port], ip[:port], cidr[:port], or *. Omit / empty / ["*"] = allow all. |
auto_pause_after_seconds | integer | No | Pause after this many seconds of inactivity (no exec, file transfer, or tunnel). Range: 60–86400. Null/omitted = never auto-pause. |
host_id | string | No | Pin to a specific host. 503 if the host can't fit the VM. |
region | string | No | Placement region. Must match the control plane's configured region; mismatched values return 400. |
Note: bandwidth_quota_bytes is not settable at create time; every sandbox starts with the cluster default (5 GiB). Use POST /v1/sandboxes/{id}/bandwidth/recharge to grow the budget.
Example request
Bash1curl -X POST https://api.sb.createos.sh/v1/sandboxes \2 -H "X-Api-Key: $CREATEOS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "shape": "s-1vcpu-1gb",6 "rootfs": "devbox:1",7 "name": "my-sandbox",8 "ingress_enabled": true,9 "auto_pause_after_seconds": 600,10 "ssh_pubkeys": ["ssh-ed25519 AAAA..."],11 "envs": { "ANTHROPIC_API_KEY": "sk-ant-..." },12 "egress": ["pypi.org", "1.1.1.1:53"]13 }'
Example response
JSON1{2 "status": "success",3 "data": {4 "id": "sb_01K...",5 "name": "my-sandbox",6 "ip": "192.168.0.12",7 "shape": "s-1vcpu-1gb",8 "rootfs": "devbox:1",9 "vcpu": 1,10 "mem_mib": 1024,11 "disk_mib": 10240,12 "spawn_ms": 87.4,13 "egress": ["pypi.org", "1.1.1.1:53"],14 "bandwidth_quota_bytes": 536870912015 }16}
Notable errors: 400 invalid body or disabled rootfs, 503 no host capacity.
GET /v1/sandboxes
List sandboxes owned by the caller (paginated).
Auth required: Yes
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max results per page (maximum 500) |
offset | integer | 0 | Pagination offset |
status | string | — | Filter by status. One of: running, creating, destroyed, failed |
Example request
Bash1curl "https://api.sb.createos.sh/v1/sandboxes?status=running&limit=10" \2 -H "X-Api-Key: $CREATEOS_API_KEY"
Example response
JSON1{2 "status": "success",3 "data": {4 "data": [5 {6 "id": "sb_01K...",7 "name": "my-sandbox",8 "status": "running",9 "ip": "192.168.0.12",10 "vcpu": 1,11 "mem_mib": 1024,12 "disk_mib": 10240,13 "shape": "s-1vcpu-1gb",14 "rootfs": "devbox:1",15 "region": "eu",16 "ingress_enabled": true,17 "auto_pause_after_seconds": 600,18 "created_at": "2026-06-17T08:00:00Z"19 }20 ],21 "pagination": {22 "total": 1,23 "limit": 10,24 "offset": 0,25 "count": 126 }27 }28}
GET /v1/sandboxes/{id}
Get details for a single sandbox.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id (sb_<ulid>) |
Example request
Bash1curl https://api.sb.createos.sh/v1/sandboxes/sb_01K... \2 -H "X-Api-Key: $CREATEOS_API_KEY"
Example response
JSON1{2 "status": "success",3 "data": {4 "id": "sb_01K...",5 "name": "my-sandbox",6 "status": "running",7 "ip": "192.168.0.12",8 "vcpu": 1,9 "mem_mib": 1024,10 "disk_mib": 10240,11 "shape": "s-1vcpu-1gb",12 "rootfs": "devbox:1",13 "region": "eu",14 "ingress_enabled": true,15 "bandwidth_ingress_bytes": 1048576,16 "auto_pause_after_seconds": 600,17 "envs": ["ANTHROPIC_API_KEY"],18 "ssh_pubkeys": ["ssh-ed25519 AAAA..."],19 "egress": ["pypi.org"],20 "created_at": "2026-06-17T08:00:00Z",21 "running_at": "2026-06-17T08:00:01Z",22 "paused_at": null,23 "last_resumed_at": null,24 "forked_from": null25 }26}
Notable errors: 404 sandbox not found.
Note: envs returns only the key names — values are never exposed via the API.
PATCH /v1/sandboxes/{id}
Partially update a sandbox. Only fields you include are changed.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
ingress_enabled | boolean | No | Toggle public ingress on or off |
auto_pause_after_seconds | integer | No | New idle-pause timeout. Range: 60–86400. Omit to leave unchanged. |
disable_auto_pause | boolean | No | Set true to turn off auto-pause entirely. Takes precedence over auto_pause_after_seconds when both are sent. |
Example request
Bash1curl -X PATCH https://api.sb.createos.sh/v1/sandboxes/sb_01K... \2 -H "X-Api-Key: $CREATEOS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{"ingress_enabled": false, "auto_pause_after_seconds": 1800}'
Example response
Returns the full updated SandboxView object (same shape as GET).
Notable errors: 400 invalid values, 404 not found.
DELETE /v1/sandboxes/{id}
Destroy a sandbox permanently.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id |
Example request
Bash1curl -X DELETE https://api.sb.createos.sh/v1/sandboxes/sb_01K... \2 -H "X-Api-Key: $CREATEOS_API_KEY"
Example response
JSON1{2 "status": "success",3 "data": {4 "id": "sb_01K...",5 "status": "destroying"6 }7}
Idempotent — deleting an already-destroyed sandbox returns the same shape with status: "destroyed". A fresh delete returns "destroying" and completes within a few seconds.
Notable errors: 404 not found.
GET /v1/sandboxes/by-ip/{ip}
Look up a sandbox by its VM IP address.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
ip | VM IP address (e.g. 192.168.0.12) |
Example request
Bash1curl https://api.sb.createos.sh/v1/sandboxes/by-ip/192.168.0.12 \2 -H "X-Api-Key: $CREATEOS_API_KEY"
Example response
Returns a SandboxView object (same shape as GET /v1/sandboxes/{id}).
Notable errors: 404 no sandbox found with that IP.