#Sandbox
A Sandbox is an isolated execution environment where you can run code, manage files, and control network access. Each sandbox is created from a Template and provides a secure, ephemeral workspace.
For shell access and file copy over standard SSH clients, see SSH.
Sandbox Model#
Key Identifiers#
| Field | Description |
|---|---|
id | Unique sandbox identifier (e.g., sb_abc123) |
template_id | Template used to create this sandbox |
team_id | Team that owns this sandbox |
user_id | User who claimed this sandbox |
pod_name | Kubernetes pod name (internal) |
cluster_id | Cluster where sandbox runs in multi-cluster deployments. Present on claim and list responses, not on sandbox detail responses. |
Lifecycle States#
| Status | Description |
|---|---|
starting | Sandbox is being initialized |
running | Sandbox is active and ready to use |
failed | Sandbox encountered an error |
completed | Sandbox has finished execution |
Pause state is modeled separately from status. Use the paused boolean when you need to distinguish a paused sandbox from a running one. For async pause/resume flows, use power_state to inspect desired vs observed state plus generation counters.
Claim a Sandbox#
Claim a sandbox from a template. The sandbox is created from a pre-warmed pool for fast startup (<200ms cold start).
/api/v1/sandboxes
Request Body#
| Field | Type | Description |
|---|---|---|
template | string | Template ID to use |
config | object | Optional sandbox configuration |
Sandbox Configuration#
| Field | Type | Description |
|---|---|---|
env_vars | object | Environment variables |
ttl | integer | Time to live in seconds (soft limit, triggers auto-pause; default: 0, disabled) |
hard_ttl | integer | Maximum lifetime in seconds (hard limit, triggers deletion; default: 0, disabled) |
network | object | SandboxNetworkPolicy. Controls traffic rules, credential bindings, and destination-scoped egress auth |
webhook | object | Webhook configuration |
auto_resume | boolean | Auto-resume when accessed (default: true) |
exposed_ports | array | Ports to expose publicly |
See Network for traffic control and Credential for outbound auth and secret handling.
TTL vs Hard TTL#
Sandbox0 uses two-tier TTL to balance resource efficiency and flexibility:
| Field | Behavior | Use Case |
|---|---|---|
ttl | Soft pause: When expired, sandbox is automatically paused. Processes stop but state is preserved. Can be extended via refresh API. | Keep sandboxes alive during active use while freeing compute resources during idle periods. |
hard_ttl | Hard delete: When expired, sandbox is permanently deleted regardless of pause state. Can also be extended via refresh API. | Enforce maximum lifetime for security or cost control. The difference from ttl is the expiration behavior (delete vs pause). |
The relationship: ttl <= hard_ttl. When ttl expires first, sandbox pauses but can be resumed.
When hard_ttl expires, sandbox is deleted immediately. Both can be extended via the refresh API.
Example timeline (sandbox created with ttl=300 and hard_ttl=3600):
t=0: Sandbox createdt=300: TTL expires → sandbox auto-pausest=310: User calls refresh → TTL reset to 300, Hard TTL reset to 3600 (new hard deadline att=3910)t=610: TTL expires again → sandbox auto-pausest=3910: Hard TTL expires → sandbox deleted
goctx := context.Background() client, err := sandbox0.NewClient( sandbox0.WithToken(os.Getenv("SANDBOX0_TOKEN")), sandbox0.WithBaseURL(os.Getenv("SANDBOX0_BASE_URL")), ) if err != nil { log.Fatal(err) } // Claim a sandbox from the "default" template sandbox, err := client.ClaimSandbox(ctx, "default", sandbox0.WithSandboxHardTTL(300), sandbox0.WithSandboxEnvVars(map[string]string{ "APP_ENV": "development", }), ) if err != nil { log.Fatal(err) } fmt.Printf("Sandbox ID: %s\n", sandbox.ID) defer client.DeleteSandbox(ctx, sandbox.ID)
Get Sandbox Details#
Retrieve full details about a sandbox.
/api/v1/sandboxes/{id}
gosb, err := client.GetSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Printf("Status: %s\n", sb.Status) fmt.Printf("Template: %s\n", sb.TemplateID) fmt.Printf("Expires at: %s\n", sb.ExpiresAt)
Get Sandbox Status#
Get the current status of a sandbox (lighter weight than full details).
/api/v1/sandboxes/{id}/status
gostatus, err := client.StatusSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Printf("Status: %s\n", status.Status.Value)
Get Sandbox Logs#
Read pod logs for sandbox startup and container diagnostics. Snapshot and streaming requests return text/plain.
/api/v1/sandboxes/{id}/logs
Query Parameters#
| Parameter | Type | Description |
|---|---|---|
container | string | Pod container name (default: procd) |
tail_lines | integer | Number of lines from the end of the log (default: 200, max: 5000) |
limit_bytes | integer | Maximum log bytes returned (default: 1048576 for snapshot responses, max: 8388608) |
follow | boolean | Stream logs as text/plain until the client disconnects |
previous | boolean | Return logs from the previously terminated container instance |
timestamps | boolean | Include Kubernetes log timestamps when available |
since_seconds | integer | Return logs newer than this many seconds |
curl -H "Authorization: Bearer $SANDBOX0_TOKEN"
"$SANDBOX0_BASE_URL/api/v1/sandboxes/sb_abc123/logs?tail_lines=200"
curl -N -H "Authorization: Bearer $SANDBOX0_TOKEN"
"$SANDBOX0_BASE_URL/api/v1/sandboxes/sb_abc123/logs?follow=true&tail_lines=50"
With follow=true, the response stays open and streams log bytes until the client disconnects.
List Sandboxes#
List all sandboxes with optional filters.
/api/v1/sandboxes
Query Parameters#
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status (starting, running, failed, completed) |
template_id | string | Filter by template ID |
paused | boolean | Filter by paused state independently of status |
limit | integer | Max results per page (default: 50, max: 200) |
offset | integer | Pagination offset (default: 0) |
golimit := 10 sandboxes, err := client.ListSandboxes(ctx, &sandbox0.ListSandboxesOptions{ Status: "running", TemplateID: "default", Limit: &limit, }) if err != nil { log.Fatal(err) } for _, sb := range sandboxes.Sandboxes { fmt.Printf("- %s (status: %s)\n", sb.ID, sb.Status) }
Update Sandbox#
Update sandbox configuration at runtime without restarting the sandbox.
/api/v1/sandboxes/{id}
Updatable Fields#
Only the following fields can be updated at runtime:
| Field | Type | Description |
|---|---|---|
ttl | integer | Time to live in seconds (soft limit) |
hard_ttl | integer | Maximum lifetime in seconds (hard limit) |
network | object | Network policy configuration |
auto_resume | boolean | Auto-resume when accessed |
exposed_ports | array | Ports to expose publicly |
env_vars and webhook cannot be updated at runtime. These fields only take effect when the sandbox is created. To use different environment variables, create a new sandbox.
go_, err = client.UpdateSandbox(ctx, sandbox.ID, apispec.SandboxUpdateRequest{ Config: apispec.NewOptSandboxUpdateConfig(apispec.SandboxUpdateConfig{ TTL: apispec.NewOptInt32(600), AutoResume: apispec.NewOptBool(false), }), }) if err != nil { log.Fatal(err) }
Pause Sandbox#
Pause a sandbox to save resources. The sandbox state is preserved.
/api/v1/sandboxes/{id}/pause
When a sandbox is paused, all processes are stopped but memory state is preserved.
Use auto_resume to automatically resume when accessed.
go_, err = client.PauseSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Println("Sandbox paused")
Resume Sandbox#
Resume a paused sandbox.
/api/v1/sandboxes/{id}/resume
go_, err = client.ResumeSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Println("Sandbox resumed")
Refresh Sandbox TTL#
Extend the sandbox time-to-live. This resets both ttl and hard_ttl (if configured) from the current time.
/api/v1/sandboxes/{id}/refresh
Request Body#
| Field | Type | Description |
|---|---|---|
duration | integer | Duration to extend TTL in seconds (optional, defaults to original TTL) |
If duration is not specified, both ttl and hard_ttl are reset to their original configured values. Use this to keep a sandbox alive as long as the user is actively using it.
go// Refresh with default duration (original TTL) resp, err := client.RefreshSandbox(ctx, sandbox.ID, nil) if err != nil { log.Fatal(err) } fmt.Printf("New expires at: %s\n", resp.ExpiresAt) // Refresh with custom duration (e.g., 1 minutes) resp, err = client.RefreshSandbox(ctx, sandbox.ID, &apispec.SandboxRefreshRequest{ Duration: apispec.NewOptInt32(60), }) if err != nil { log.Fatal(err) } fmt.Printf("New expires at: %s\n", resp.ExpiresAt)
Delete Sandbox#
Terminate and delete a sandbox. This action is irreversible.
/api/v1/sandboxes/{id}
go_, err = client.DeleteSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Println("Sandbox deleted")
Next Steps#
Contexts
Run commands and manage processes (REPL and Cmd)
Files
Read, write, and manage files in sandboxes
SSH
Connect with standard ssh and transfer files with scp
Network Policy
Control network access and egress rules