---
title: "Sandboxes · API reference · Promigence"
description: "The Promigence API's sandboxes routes: 10 in all, with parameters, request bodies and answers."
url: "https://www.promigence.ai/docs/reference/api/sandboxes"
site: "Promigence"
---

[API reference](https://www.promigence.ai/docs/reference/api)

# Sandboxes

10 routes of the published API contract, generated from it.

### GET/v1/sandboxes

Auth: API key

List your org's sandboxes, newest first. `?labels=k=v,k2=v2` returns only those whose run carries every label given, and `?state=running,ready` narrows by state: `queued` is every sandbox still waiting to start, `awaiting_capacity` only those a run answer reports as waiting for capacity. Both filters run on the server, so they find a match older than one page — which is how two copies of your service agree on one sandbox instead of each starting its own. Pages are `?limit=N` (1..=500, default 50) and `?cursor=`; echo back `next_cursor` to get the next page, and stop when it is `null`. A short page is not the end: a filter can empty a page that still has more behind it.

#### Parameters

cursorquery · string

labelsquery · string

limitquery · integer

statequery · string

#### Answer 200 · SandboxList · application/json

labelsrequiredmap of string

The label filter this list was produced with; empty when none was given.

limitrequiredinteger

The page size that was applied.

next_cursorstring | null

Pass back as `?cursor=` for the next page; `null` on the last page. A short page is not the end: a filter can empty a page that still has more behind it.

sandboxesrequiredSandboxView[]

staterequiredstring[]

The state filter this list was produced with; empty when none was given. `queued` keeps every waiting sandbox; `awaiting_capacity` only those waiting for capacity being added.

### GET/v1/sandboxes/{id}

Auth: API key

One sandbox, with its execs. `auto_pause_s` and `auto_pause_mode` report the idle rule it is under — the values `PATCH` sets; `auto_pause_s` is 0 when it never pauses itself on idle. `optimize_for` is what the sandbox asked for; `optimize_for_applied` is what its latest start or resume actually got (null before the first). They can differ — the next resume asks again.

#### Parameters

idrequiredpath · string

#### Answer 200 · SandboxView · application/json

attemptrequiredinteger

1 for the first try, 2 for the first retry, and so on.

auto_pause_moderequiredstring

What idle means for the rule: `requests` | `activity`.

auto_pause_srequiredinteger

The idle rule it is under: park after this many idle seconds, 0 for never.

billable_secondsinteger | null

Once it has ended, the seconds it is billed for (the run report's `billable_seconds`). Present on `GET /v1/sandboxes/{id}` for an ended sandbox; absent from list rows.

cost_usdnumber | null

What it has cost in USD at its run's rates: once it has ended, the run report's `cost`; while it is live, the seconds billed so far (running time only). Present on `GET /v1/sandboxes/{id}` once it has started; absent from list rows.

created_atrequiredstring

When the sandbox was created, RFC 3339: when its run was started, or when the retry or replay that made it was asked for.

e2e_msnumber | null

Milliseconds from the start request, after any time queued, to the sandbox being handed over: it does not include `queued_ms`. Add `queued_ms` for the whole wait.

egressrequiredEgressCounters

Data out, and whether it was cut for the organisation's monthly cap.

elapsed_msinteger | null

Milliseconds of running time since hand-over, time spent paused excluded: what `timeout_ms` is measured against, so `timeout_ms - elapsed_ms` is the time it has left. `null` before hand-over and once it has ended.

env_verifiedrequiredboolean

Whether this sandbox's environment passed its checks.

eta_sinteger | null

Seconds until this sandbox is expected to start, with `queued_reason: capacity_arriving`. `null` with the other reasons, and once the sandbox has waited longer than the estimate it was first given; `queued_message` then says it is taking longer than expected rather than repeating a number.

execsExecView[] | null

The commands run in this sandbox. Present on `GET /v1/sandboxes/{id}`; absent from the rows of a list, which would otherwise carry every byte of every command's output.

failureobject

What went wrong, rendered against this sandbox's own evidence. `null` on success.

labelsrequiredmap of string

Inherited from the run. A caller that looked a sandbox up by label needs to see the labels it got back, and one that did not needs a way to learn what a sandbox is tagged with.

one_timeboolean | null

True when this is a one-time wait: once the waiting sandboxes can start, the rest of the run starts at once too. False otherwise.

optimize_forrequiredOptimizeFor

What the sandbox asked for.

optimize_for_appliedOptimizeFor | null

What its latest start or resume actually got; `null` before the first.

outcomestring | null

Why it ended; `null` while it is still alive.

pause_expires_atstring | null

While it is paused: when it will be deleted, with its files and state, unless it is resumed before then (RFC 3339). A paused sandbox is kept for 30 days, and resuming it starts the 30 days again. Absent while it is not paused, and for a paused sandbox that is not due to be deleted.

pause_reasonstring | null

Why it is paused, when a limit paused it rather than a request: `spend_cap` (its run reached its spend cap) or `credits_exhausted` (the organization's credits ran out). Its files and state are kept and paused time is not billed; it resumes once the cap is raised or credits are added. Absent otherwise.

queued_messagestring | null

The same, in words, ready to show a person.

queued_msnumber | null

Milliseconds spent waiting for capacity.

queued_reasonQueuedReason | null

ready_msnumber | null

Milliseconds until the sandbox was ready to take work.

replay_ofstring | null

The sandbox this one is a replay of.

retried_bystring | null

The retry that replaced this sandbox, if it was retried.

retry_ofstring | null

The sandbox this one is a retry of.

run_idrequiredstring

The run this sandbox belongs to.

sandbox_idrequiredstring

snapshot_idrequiredstring

The snapshot it was started from, as its run names it (`GET /v1/runs/{id}`): the snapshot's id, or `promigence/base` for the built-in base.

staterequiredstring

`queued` | `ready` | `running` | `paused` | `ended`.

t_endstring | null

When it ended, RFC 3339.

t_handoffstring | null

When the sandbox was handed over, RFC 3339.

timeout_msinteger | null

The lifetime this sandbox is bound to, in milliseconds of running time: time spent paused does not count. A `PATCH` with a larger `timeout_ms` extends it.

verify_each_msnumber | null

Milliseconds the per-sandbox verification took, when `verify_each` was asked for.

warningsrequiredstring[]

### PATCH/v1/sandboxes/{id}

Auth: API key

Extend a live sandbox's total lifetime, and set when it parks itself. `timeout_ms` sets the total, not an offset from now; 409 `cap_exceeded` if the extra seconds do not fit the run's cap. `auto_pause_s` parks the sandbox once it has been idle that long — 0 turns it off, the minimum is 2, and a sandbox with a command, a background command, a terminal or an SSH session still open is never idle, so a long build or a dev server is safe. `auto_pause_mode` says what idle means: `requests` (the default) counts calls to the sandbox; `activity` also waits until, for the whole window, nothing inside has used CPU or sent or received a byte, and no network connection to the outside is open — for an agent that runs inside the sandbox on its own. Start such an agent in the background of a command that returns: it keeps running when the sandbox wakes. An agent still running as an open command keeps the sandbox awake in either mode, because a pause would end it. A sandbox parked by this rule wakes by itself on its next command or file call, and parked time is not billed. Any of the fields may be sent on its own.

#### Parameters

idrequiredpath · string

#### Request body SandboxPatch · application/json · optional

auto_pause_modeAutoPauseMode | null

auto_pause_sinteger | null

Pause after this many idle seconds; 0 turns the rule off.

timeout_msinteger | null

The new lifetime in milliseconds, counted from now.

#### Answer 200 · SandboxPatched · application/json

### DELETE/v1/sandboxes/{id}

Auth: API key

Kill it now. The answer's `outcome` says how it ended: `aborted_by_client` for a sandbox that had started, billed for the seconds it used; `not_started` for one still queued, which is not billed; or, when its command had already returned, that command's own outcome. A sandbox that had already ended answers with the outcome it ended with and `already_ended: true`.

#### Parameters

idrequiredpath · string

#### Answer 200 · SandboxKilled · application/json

already_endedrequiredboolean

True when the sandbox had already ended and this call changed nothing.

okrequiredboolean

outcomestring | null

sandbox_idrequiredstring

staterequiredstring

`"ended"`.

### GET/v1/sandboxes/{id}/network

Auth: API key

Read the network policy a live sandbox is running under.

#### Parameters

idrequiredpath · string

#### Answer 200 · SandboxNetwork · application/json

networkrequiredobject

`"egress"`, `"none"`, or `{"allow": [...]}` — the policy in force: as it was written, or `"none"` once the sandbox's egress has been cut.

refused_connectionsobject

Connections refused, counted, including those to a bare address (which have no name to list and whose addresses are not recorded). Only for a sandbox that is still running.

refused_hostsrequiredobject

The hosts this sandbox was refused, by name. Current while it is running, and as recorded once it is not. A connection to a bare address has no name: it is counted in `refused_connections`, not listed here.

refused_lookupsobject

Name lookups refused. Only for a sandbox that is still running.

sandbox_idrequiredstring

staterequiredstring

via_secretViaSecret[]

The hosts this sandbox may reach for its host-bound secrets (`secrets set --host`), each secret by name with its hosts, whatever `network` says. Absent when it has none.

### POST/v1/sandboxes/{id}/network

Auth: API key

Cut a live sandbox's egress. Use it to fetch dependencies first and close the network before the agent runs. One direction only: there is no call that opens egress again, so a sandbox can never widen its own access.

#### Parameters

idrequiredpath · string

#### Request body SandboxNetworkSet · application/json

networkrequiredstring

`none`, the only value.

#### Answer 200 · SandboxNetworkCut · application/json

appliedrequiredboolean

False if the sandbox was already running with no egress.

networkrequiredNetworkMode

A network policy named by its mode alone.

sandbox_idrequiredstring

staterequiredstring

### POST/v1/sandboxes/{id}/pause

Auth: API key

Park the sandbox: it does not count against your concurrency limit, and paused time is not billed. Background commands started with `background: true` are ended by the pause, and the answer says how many (`background_execs_killed`, only when there were any); start them again after resume. A sandbox that was given the value of a secret pauses as usual, and the answer carries a `secrets_in_saved_state` warning.

#### Parameters

idrequiredpath · string

#### Answer 200 · SandboxPaused · application/json

already_pausedboolean | null

Present, and true, only when the sandbox was already paused and this call changed nothing. The fields below it are then absent.

background_execs_killedinteger | null

Background commands the pause ended, when there were any. A pause does not keep a running background command: start it again after resume.

bytesParkedBytes | null

What the parked sandbox occupies on disk while it is not running.

durableboolean | null

True when the parked state is kept safe from a failure on our side. `false` is not an error.

okrequiredboolean

paused_idstring | null

An opaque name for this pause. Resume by the sandbox id; this one is for your records.

recordedboolean | null

False if the sandbox was parked but the change could not be written down, which is worth retrying.

sandbox_idrequiredstring

staterequiredstring

`"paused"`.

took_msinteger | null

Milliseconds the pause took, from the request to the answer.

warningsstring[] | null

Things to know about what was parked, one `code: sentence` per line; only when there is one. Today the only one is `secrets_in_saved_state`.

### POST/v1/sandboxes/{id}/probe

Auth: API key

Re-check the sandbox's files against what the verified snapshot recorded. `first_bad_path` is the first path that differs.

#### Parameters

idrequiredpath · string

#### Request body SandboxProbeRequest · application/json · optional

pathsstring[]

Paths to check; omitted, the whole workspace.

#### Answer 200 · SandboxProbe · application/json

checkedrequiredobject

What was checked: the list you asked for, or the string `"verified_paths"` for the snapshot's own recorded set.

first_bad_pathstring | null

The first path that differs, and the only part of a failed check anyone can act on.

msrequirednumber

How long the check took, in milliseconds.

okrequiredboolean

True when every path checked still matches what was verified.

sandbox_idrequiredstring

### POST/v1/sandboxes/{id}/resume

Auth: API key

Bring a paused sandbox back where it was, and restart the billing clock.

#### Parameters

idrequiredpath · string

#### Request body SandboxResume · application/json · optional

optimize_forOptimizeFor | null

Omitted: the sandbox's own setting.

spend_capnumber | null

For a sandbox paused at its run's spend cap (`pause_reason: spend_cap`): the run's new cap in US dollars, above the one it reached. The sandbox goes on with what the new cap leaves, up to its own timeout.

#### Answer 200 · SandboxResumed · application/json

notestring | null

What `restarted` means for this sandbox, in one sentence. Absent for a normal resume.

okrequiredboolean

paused_idrequiredstring

The pause that was restored: the `paused_id` its pause answered with.

recordedrequiredboolean

False if the sandbox came back but the change could not be written down.

restartedboolean

True when the sandbox came back from its saved files only: its files are as they were when it paused, but the programs that were running then were not kept and start fresh. Absent (false) for a normal resume, where everything comes back as it was.

sandbox_idrequiredstring

staterequiredstring

`"ready"`.

took_msrequiredinteger

Milliseconds the resume took, from the request to the answer.

### POST/v1/sandboxes/{id}/snapshot

Auth: API key

Snapshot a running sandbox without stopping it, and get back an ordinary snapshot id you can fork. Background processes are ended first and the count is in the reply. The new snapshot inherits the tier and source of the snapshot this sandbox came from. It is not marked verified: the sandbox has run your code since, so verification has to be earned again rather than inherited. A sandbox that was given the value of a secret is refused with `secrets_in_snapshot` (409), because the snapshot, and every sandbox started from it, could contain that value; `force: true` takes it anyway and the answer carries a `secrets_in_saved_state` warning. An `alias` another snapshot already has is refused unless `move_alias: true` moves it here (the other snapshot stays, unnamed).

#### Parameters

idrequiredpath · string

#### Request body SandboxSnapshotCreate · application/json · optional

aliasstring | null

A name for the new snapshot, unique in the project.

forceboolean

Take it even though the sandbox was given a secret's value.

move_aliasboolean

If another snapshot has `alias`, move the name to the new one (the other stays, unnamed). Without it such an alias is refused.

#### Answer 200 · SandboxSnapshot · application/json

aliasstring | null

background_execs_killedrequiredinteger

Background processes ended to take the snapshot. Reported rather than silent: a live snapshot must not quietly cost a customer their dev server.

bytesrequiredSnapshotBytes

What the image occupies on disk.

okrequiredboolean

sandbox_idrequiredstring

The sandbox that was photographed. Still yours, still running.

snapshot_idrequiredstring

An ordinary snapshot id, forkable by every path that forks anything else. There is deliberately no second kind of snapshot: a parallel identifier with its own rules is how two code paths drift apart.

still_runningrequiredboolean

Always `true` on a 200. See the type's note.

tierrequiredstring

took_msrequiredinteger

Milliseconds the snapshot took, from the request to the answer.

warningsstring[]

Things the caller should know about what was taken, one `code: sentence` per line. Absent when there are none. Today the only one is `secrets_in_saved_state`: the sandbox had been given the value of a secret and the snapshot was taken with `force`, so the snapshot, and every sandbox started from it, can contain that value.

[Every route](https://www.promigence.ai/docs/reference/api) · [what each error means and whether it was billed](https://www.promigence.ai/docs/errors)
