Sandboxes

Understanding the sandbox lifecycle and available operations
View as Markdown

A sandbox is the core primitive in Modbox — a running container instance with its own URL, lifecycle, and resource limits.

Lifecycle

┌──────────────────────────────────────┐
provision ───► │ PROVISIONING │
│ Modbox is scheduling the container │
└──────────────┬───────────────────────┘
│ sandbox ready
▼
┌──────────────────────────────────────┐
│ RUNNING │
│ sandbox_url is accessible │
└──────────────┬───────────────────────┘
│ destroy() or TTL expires
▼
┌──────────────────────────────────────┐
│ DESTROYED │
│ all sandbox resources deleted │
└──────────────────────────────────────┘

Provision

Create a new sandbox. This is always async — the API returns immediately with status: provisioning.

POST /sandboxes/provision
{
"task_id": "my-sandbox", // unique identifier — used to reference the sandbox
"image_id": "uuid-of-your-image", // optional, uses workspace default if omitted
"ttl_seconds": 300, // optional, auto-destroy after this many seconds
"env_vars": { // optional, injected into the container
"MY_VAR": "my-value"
}
}

The task_id is your identifier for the sandbox. Choose something meaningful like agent-{session_id} or pr-{pr_number}.

Wait for ready

After provisioning, poll for ready or use the blocking wait endpoint:

# Option A: blocking wait (recommended)
POST /sandboxes/wait
{ "task_id": "my-sandbox", "timeout": 120 }
# Option B: poll the detail endpoint
GET /sandboxes/detail/{sandbox_id}

Once status is running, the sandbox_url field contains the live HTTPS endpoint.

List sandboxes

GET /sandboxes
GET /sandboxes?status=running
GET /sandboxes?status=provisioning

Pass X-Workspace-Id to filter by workspace.

Destroy

POST /sandboxes/destroy
{ "task_id": "my-sandbox" }

This immediately deletes all sandbox resources. The sandbox moves to status: destroyed.

TTL (time-to-live)

If a ttl_seconds is set when provisioning, the sandbox is automatically destroyed after that many seconds — even if you never call destroy. This is the recommended way to avoid resource leaks.

{
"task_id": "my-sandbox",
"ttl_seconds": 3600
}

Always set a TTL for agent-driven sandboxes. If your agent crashes or your backend goes down, the sandbox will still be cleaned up automatically.

Sandbox fields

FieldTypeDescription
idUUIDInternal sandbox ID
namestringSame as your task_id
statusprovisioning | running | destroyedCurrent lifecycle state
sandbox_urlstringHTTPS URL of the running sandbox (only when running)
imagestringDocker image tag used
created_bystringUser ID of the provisioning user
created_atdatetimeWhen provisioning was requested
destroyed_atdatetimeWhen the sandbox was destroyed (if applicable)