Pause, Resume & Fork
Snapshot a sandbox to free its host, restore it later, or clone it into a new independent identity.
At a glance
- Base URL:
https://api.sb.createos.sh - Auth:
X-Api-Key: <token>header. Get a token - Response envelope: JSend,
{"status": "...", "data": ...}
State preserved on pause
Pausing snapshots the full VM state to object storage:
- Disk: filesystem contents
- Memory: full RAM image (processes, open files, network connections)
- CPU state: exact register values and execution context
Pause releases live compute while preserving the snapshot. Resume can use the same host or another compatible host. A cached snapshot can resume faster than one that must be fetched from storage; timing depends on snapshot size, cache state, and load. Applications should reconnect external network connections after resume.
POST /v1/sandboxes/{id}/pause
Pause a running sandbox, preserving disk and memory state.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id (must be running) |
Returns 202 Accepted with the sandbox in pausing status. Poll GET /v1/sandboxes/{id} until status flips to paused. Completion time depends on snapshot size and storage performance. Calling pause on an already paused sandbox returns 409; check its status before retrying.
The response header X-Poll-After carries the suggested number of seconds to wait before the first poll.
Example request
curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb-01K.../pause \
-H "X-Api-Key: $CREATEOS_API_KEY"Example response (202)
{
"status": "success",
"data": {
"id": "sb-01K...",
"status": "pausing"
}
}Notable errors: 409 sandbox is not running.
A sandbox can also pause itself from the inside with no API key, see Self-Signal.
POST /v1/sandboxes/{id}/resume
Resume a paused sandbox.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id (must be paused or error) |
Returns 202 Accepted with the sandbox in resuming status. Poll GET /v1/sandboxes/{id} until status flips to running. The server retries on different hosts if the first attempt fails. If all retry attempts are exhausted the row goes to error. POST /resume again to try with a fresh budget.
Calling resume on an already running sandbox returns 409; check its status before retrying.
Resume checks your sandbox quota, excluding the sandbox being resumed from that count. Other non-terminal sandboxes, including paused ones, count toward the cap. If they fill the cap, resume returns 429. Destroy an unneeded sandbox to free a slot.
Example request
curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb-01K.../resume \
-H "X-Api-Key: $CREATEOS_API_KEY"Example response (202)
{
"status": "success",
"data": {
"id": "sb-01K...",
"status": "resuming"
}
}Notable errors: 409 sandbox is not paused or in error, 429 sandbox quota reached, 402 insufficient credit, 503 no host with capacity.
POST /v1/sandboxes/{id}/fork
Clone a paused sandbox into a new, independent sandbox identity.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Source sandbox id, must be paused |
Fork copies the snapshot into a new sandbox with:
- Separate sandbox id and IP address
- Separate bandwidth ledger
- Separate placement (may land on a different host)
By default the new sandbox auto-resumes to running. Pass start_paused: true to keep it in paused.
Request body (optional)
| Field | Type | Required | Description |
|---|---|---|---|
start_paused | boolean | No | Keep the new sandbox paused after the bundle copy completes. Default false (auto-resumes to running). |
ssh_pubkeys | string[] | No | SSH public keys to authorize on the new sandbox. |
egress | string[] | No | Outbound allowlist for the new sandbox. |
ingress_enabled | boolean | No | Enable public ingress on the new sandbox. |
envs | object | No | A nonempty map replaces the inherited environment map. Omit or send an empty map to inherit the source environment. |
The child starts with the deployment's default bandwidth allowance. Supplying bandwidth_quota_bytes returns 400, including when its value is zero. Recharge after the child reaches running to increase its quota.
S3 disk attachments do not carry over. Fork has no disks request field: wait for the child to run, then attach the registered disks it needs.
Example request
curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb-01K.../fork \
-H "X-Api-Key: $CREATEOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"start_paused": true}'Example response (202)
{
"status": "success",
"data": {
"id": "sb-01KNEW...",
"name": "brave-otter",
"status": "forking",
"shape": "s-1vcpu-1gb",
"vcpu": 1,
"mem_mib": 1024,
"disk_mib": 10240,
"forked_from": "sb-01K..."
}
}The response carries the new sandbox id under data. Use X-Poll-After to choose when to start polling that id. Wait for paused when start_paused is true, or running otherwise. The initial response does not include an allocated IP.
Notable errors: 400 unsupported bandwidth override, 409 source sandbox is not paused, 402 insufficient credit, 429 sandbox quota reached, 503 fork unavailable.
Polling pattern
All three lifecycle operations are asynchronous. Use this pattern to wait for completion:
ID="sb-01K..."
# Trigger the operation (e.g. resume)
curl -X POST "https://api.sb.createos.sh/v1/sandboxes/$ID/resume" \
-H "X-Api-Key: $CREATEOS_API_KEY"
# Poll until running
while true; do
STATUS=$(curl -s "https://api.sb.createos.sh/v1/sandboxes/$ID" \
-H "X-Api-Key: $CREATEOS_API_KEY" | jq -r '.data.status')
echo "status: $STATUS"
[ "$STATUS" = "running" ] && break
[ "$STATUS" = "error" ] && { echo "resume failed"; exit 1; }
sleep 2
doneRelated
- What pause costs and what it preserves: Limits & defaults (lifetime, idle and cleanup).
- Why fork matters for agents: Fork your agent's state. Product page: CreateOS Sandbox.
- SDK equivalents: Pause, Fork & Auto-Pause.