Documentation/docs/sandbox

#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.

Sandbox0 Cloud clients should use https://api.sandbox0.ai. Set SANDBOX0_BASE_URL only when you are connecting to a self-hosted or private deployment.

Sandbox Model#

Key Identifiers#

FieldDescription
idUnique sandbox identifier (e.g., sb_abc123)
template_idTemplate used to create this sandbox
team_idTeam that owns this sandbox
user_idUser who claimed this sandbox
pod_nameKubernetes pod name (internal)
cluster_idCluster where sandbox runs in multi-cluster deployments. Present on claim and list responses, not on sandbox detail responses.

Lifecycle States#

StatusDescription
startingSandbox is being initialized
runningSandbox is active and ready to use
failedSandbox encountered an error
completedSandbox 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).

POST

/api/v1/sandboxes

Request Body#

FieldTypeDescription
templatestringTemplate ID to use
configobjectOptional sandbox configuration

Sandbox Configuration#

FieldTypeDescription
env_varsobjectSandbox-level default environment variables for new procd-managed processes
ttlintegerTime to live in seconds (soft limit, triggers auto-pause; default: 0, disabled)
hard_ttlintegerHard runtime lifetime in seconds (cleans compute while preserving sandbox identity and services; default: 0, disabled)
networkobjectSandboxNetworkPolicy. Controls traffic rules, protocol controls, credential bindings, and destination-scoped egress auth
webhookobjectWebhook configuration
auto_resumebooleanAuto-resume when accessed (default: true)
servicesarraySandbox Services for public HTTP routes, including Sandbox Functions

See Network and Protocol Controls for outbound control, Sandbox Services for public HTTP controls, Sandbox Functions for inline public handlers, and Credential for outbound auth and secret handling.

Sandbox env_vars override template/container environment variables for new contexts, command services, and function executions. Per-context, per-command, service runtime, and function env_vars override sandbox env_vars for that narrower scope. Warm processes start before the sandbox is claimed, so they do not receive claim-time sandbox env_vars.

TTL vs Hard TTL#

Sandbox0 uses two-tier TTL to balance resource efficiency and flexibility:

FieldBehaviorUse Case
ttlSoft 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_ttlHard clean: When expired, Sandbox0 deletes the runtime pod and marks the sandbox cleaned. Identity, configuration, services, and public URLs remain available until explicit delete.Enforce compute cost limits while keeping a durable sandbox service that can be restored on demand.

The relationship: ttl <= hard_ttl. When ttl expires first, sandbox pauses but can be resumed. When hard_ttl expires, sandbox compute is cleaned and the sandbox can be restored by resume-capable access. Both can be extended via the refresh API.

Example timeline (sandbox created with ttl=300 and hard_ttl=3600):

  • t=0: Sandbox created
  • t=300: TTL expires → sandbox auto-pauses
  • t=310: User calls refresh → TTL reset to 300, Hard TTL reset to 3600 (new hard deadline at t=3910)
  • t=610: TTL expires again → sandbox auto-pauses
  • t=3910: Hard TTL expires → runtime pod cleaned, sandbox status becomes cleaned
go
ctx := 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.

GET

/api/v1/sandboxes/{id}

go
sb, 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).

GET

/api/v1/sandboxes/{id}/status

go
status, err := client.StatusSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Printf("Status: %s\n", status.Status.Value)

Get Sandbox Logs#

Read sandbox process output. Procd service logs are filtered out of this API and remain available from Kubernetes pod logs. Snapshot and streaming requests return text/plain.

GET

/api/v1/sandboxes/{id}/logs

Query Parameters#

ParameterTypeDescription
containerstringPod container name (default: procd)
tail_linesintegerNumber of Kubernetes log lines read from the end of the log before procd service log filtering (default: 200, max: 5000)
limit_bytesintegerMaximum Kubernetes log bytes read before procd service log filtering (default: 1048576 for snapshot responses, max: 8388608)
followbooleanStream logs as text/plain until the client disconnects
previousbooleanReturn logs from the previously terminated container instance
timestampsbooleanInclude Kubernetes log timestamps when available
since_secondsintegerReturn logs newer than this many seconds
go
tailLines := int64(200) logs, err := sandbox.GetLogs(ctx, &sandbox0.SandboxLogsOptions{ TailLines: &tailLines, }) if err != nil { log.Fatal(err) } fmt.Print(logs.Logs)

For live streaming, use sandbox.StreamLogs(...), sandbox.stream_logs(...), sandbox.streamLogs(...), or s0 sandbox logs --follow.


List Sandboxes#

List all sandboxes with optional filters.

GET

/api/v1/sandboxes

Query Parameters#

ParameterTypeDescription
statusstringFilter by status (starting, running, failed, completed, terminating)
template_idstringFilter by template ID
pausedbooleanFilter by paused state independently of status
limitintegerMax results per page (default: 50, max: 200)
offsetintegerPagination offset (default: 0)
go
limit := 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.

PUT

/api/v1/sandboxes/{id}

Updatable Fields#

Only the following fields can be updated at runtime:

FieldTypeDescription
ttlintegerTime to live in seconds (soft limit)
hard_ttlintegerHard runtime lifetime in seconds
networkobjectNetwork policy configuration
auto_resumebooleanAuto-resume when accessed
servicesarraySandbox Services for public HTTP routes, including Sandbox Functions

env_vars and webhook cannot be updated at runtime. These fields only take effect when the sandbox is created. To use different sandbox-level 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 And Resume#

Pause and resume is covered in a dedicated page because it affects TTL, auto_resume, service routes, SSH, and webhook behavior.

See Pause And Resume for explicit pause, state inspection, resume, and auto-resume behavior.


Refresh Sandbox TTL#

Extend the sandbox time-to-live. This resets both ttl and hard_ttl (if configured) from the current time while the sandbox has a runtime.

POST

/api/v1/sandboxes/{id}/refresh

Request Body#

FieldTypeDescription
durationintegerDuration 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 minute) 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.

DELETE

/api/v1/sandboxes/{id}

go
_, err = client.DeleteSandbox(ctx, sandbox.ID) if err != nil { log.Fatal(err) } fmt.Println("Sandbox deleted")

Next Steps#

Pause And Resume

Control sandbox power state and resume behavior before wiring long-lived workflows.

Contexts

Run REPL and command contexts inside a sandbox and stream process output.