Sandboxes

Understanding the sandbox lifecycle and available operations
View as MarkdownOpen in Claude

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
1{
2 "task_id": "my-sandbox", // unique identifier — used to reference the sandbox
3 "image_id": "uuid-of-your-image", // optional, uses workspace default if omitted
4 "ttl_seconds": 300, // optional, auto-destroy after this many seconds
5 "env_vars": { // optional, injected into the container
6 "MY_VAR": "my-value"
7 }
8}

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.

1{
2 "task_id": "my-sandbox",
3 "ttl_seconds": 3600
4}

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)