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

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

# Runs

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

### DELETE/v1/captures/{id}

Auth: API key

Destroy a preserved failure now. The bytes are deleted before the answer says so.

#### Parameters

idrequiredpath · string

#### Answer 200 · CaptureDeleted · application/json

bytesrequiredinteger

Bytes freed.

deletedrequiredboolean

deleted_atrequiredstring

RFC 3339.

okrequiredboolean

snapshot_idrequiredstring

### GET/v1/runs

Auth: API key

List your org's runs, newest first. Pages are `?limit=N` (1..=500, default 50) and `?cursor=`; echo back `next_cursor` and stop when it is `null`.

#### Parameters

cursorquery · string

limitquery · integer

#### Answer 200 · RunList · application/json

next_cursorstring | null

Pass as `?cursor=` for the next page; `null` on the last one.

runsrequiredRunView[]

### POST/v1/runs

Auth: API key

Fork N sandboxes from one snapshot, optionally running a command in each. Refused with 409 `cap_exceeded` before anything starts if the quote exceeds `spend_cap`. `?wait_ms=N` parks until the sandboxes are ready; honours `Idempotency-Key`.

#### Parameters

wait_msquery · integer

Idempotency-Keyheader · string

Makes a retried create safe: send the same key on every attempt of ONE create and it starts, and bills, once. Kept 24 hours per org. The same key with the same request (method, path and JSON body) answers with the first answer — same status, same ids — marked `Idempotent-Replayed: true`. The same key with a different request is refused with 409 `idempotency_key_reused`. A repeat that arrives while the first is still running waits for its answer, or gets 409 `idempotency_key_in_use` with `Retry-After`. Only an answer that started something is kept: a create refused before anything started leaves the key free. The SDKs send one for every create they make.

#### Request body RunCreate · application/json

allow_partialboolean

Start what fits now rather than refusing the whole run.

captureCaptureMode | null

countrequiredinteger

How many sandboxes, 1–1000.

execExecCreate | null

A command each sandbox runs as it starts; the sandbox's outcome is its exit.

gradeGradeSpec | null

Score each sandbox's work after its command.

grade_outputboolean | null

Keep what the grader prints: the last 16 KiB of its output, stdout and stderr together, in each graded sandbox's `grade.output` in the run report. Never a held-out grader's. Absent: the setting of the snapshot's default grader when the run uses it, otherwise off. Needs a grader (`grade`, or the snapshot's default).

labelsmap of string

Your own key/value labels, returned on every answer about the run.

networkNetworkRequest | null

optimize_forOptimizeFor | null

preemptibleboolean

The lower batch rate: the run's sandboxes can be stopped early.

secretsSecretUse[]

Stored secrets every command in the run's sandboxes receives.

snapshotrequiredstring

A snapshot id, alias, `alias@commit7`, or `promigence/base`.

spend_capnumber | null

The most the run may cost, in USD.

tierstring | null

The sandbox size. Default: the snapshot's.

timeout_msinteger | null

Each sandbox's lifetime in milliseconds. Default 15 minutes, at most 30 days.

verify_eachboolean

Re-run the snapshot's verification in each sandbox before it takes work.

#### Answer 200 · RunCreated · application/json

countrequiredinteger

How many sandboxes were asked for.

idempotent_replayrequiredboolean

True when this is the stored answer to an `Idempotency-Key` that was seen before, and no second run was started.

idempotent_replay_age_sinteger | null

Present when `idempotent_replay` is true: how many seconds ago that first answer was given, so a client can say which earlier request this repeats.

launchedrequiredinteger

How many were started. Fewer than `count` only with `allow_partial`, and the reason is in `warnings`.

preemptiblerequiredboolean

True when the run was posted at the preemptible rate: its sandboxes can be stopped early, and one stopped that way bills nothing.

quoterequiredQuote

A quote, per second: `max_cost = Σ sandbox_count × seconds_per_sandbox × per_second_usd`, where `per_second_usd = vcpus × vcpu_second_usd + mem_gib × gib_second_usd`. The most the run can cost if every sandbox runs its whole timeout; billing is for the seconds actually used.

run_idrequiredstring

sandboxesrequiredRunSandboxRef[]

snapshotrequiredstring

The snapshot, resolved.

snapshot_argrequiredstring

The snapshot as you named it — an id, an alias, or a path.

snapshot_idstring | null

The snapshot's id, as `GET /v1/runs/{id}` and the report give it: `""` for the built-in base. Never `null` from this API; typed nullable for older answers.

spend_caprequirednumber

The most this run may cost, in USD.

staterequiredstring

`"running"`.

tierrequiredstring

timeout_msrequiredinteger

warningsrequiredstring[]

What was **not** started and why, said when it is decided rather than discovered in the report.

### GET/v1/runs/{id}

Auth: API key

One run and its sandboxes. `?wait_ms=N` long-polls until the run is finished, or every sandbox has ended or outlived its command (`kill_on_exit: false`, `command_outcome` set).

#### Parameters

idrequiredpath · string

wait_msquery · integer

#### Answer 200 · RunView · application/json

canceledrequiredboolean

capacityCapacity | null

Only on `GET /v1/runs/{id}`: whether the waiting sandboxes can start, so a client that is already long-polling this route does not need a second call to find out why it is waiting.

capturerequiredstring

What this run does with a sandbox's state when it ends: `on_failure` | `off` | `always`. Stated on every answer, so nobody has to remember what the default was.

countrequiredinteger

How many sandboxes were asked for.

countsobject | null

How many sandboxes are in each state, keyed by state or by outcome. Only on `GET /v1/runs/{id}`.

execobject

The command each sandbox was created with, if any.

finished_atstring | null

RFC 3339; `null` while the run is still going.

gradeobject

The grading block this run was submitted with, if any.

grade_outputboolean

The run keeps what its grader prints (`grade_output`). Absent when it does not.

labelsrequiredmap of string

networkrequiredobject

The policy as it was submitted: `"egress"` / `"none"` stay strings, an allowlist comes back as the object you sent, normalised.

quoterequiredRunQuote

The price a run was quoted at, frozen when it started. The same numbers `POST /v1/runs/quote` answers with, without the per-line breakdown: a run that exists has one line.

run_idrequiredstring

sandboxesRunSandboxRef[] | null

Only on `GET /v1/runs/{id}`: one compact row per sandbox. The full records, with their timings, are `GET /v1/runs/{id}/sandboxes`.

snapshotrequiredstring

The snapshot this run forks from, as it was asked for.

snapshot_idrequiredstring

The same value under the name the validity report uses. Both are sent so a client can read either.

spend_caprequirednumber

The most this run may cost, in USD.

started_atrequiredstring

RFC 3339.

staterequiredstring

`queued` | `running` | `completed` | `aborted`.

tierrequiredstring

timeout_msrequiredinteger

Each sandbox's lifetime, in milliseconds.

verify_eachrequiredboolean

Whether each sandbox re-ran the snapshot's own verification before taking work.

### DELETE/v1/runs/{id}

Auth: API key

Cancel the queue and kill every live sandbox of the run.

#### Parameters

idrequiredpath · string

#### Answer 200 · RunKilled · application/json

killedrequiredinteger

How many live sandboxes were killed. Each is billed for the seconds it used.

okrequiredboolean

run_idrequiredstring

### POST/v1/runs/{id}/cancel

Auth: API key

Stop what is still queued. Live sandboxes keep running — use `DELETE /v1/runs/:id` for those.

#### Parameters

idrequiredpath · string

#### Answer 200 · RunCanceled · application/json

canceledrequiredinteger

How many queued sandboxes were dropped. They were never started, so they are not billed.

okrequiredboolean

run_idrequiredstring

### GET/v1/runs/{id}/captures

Auth: API key

What is preserved of this run's failures, and when each goes.

#### Parameters

idrequiredpath · string

#### Answer 200 · CaptureList · application/json

capturesrequiredCaptureView[]

okrequiredboolean

run_idrequiredstring

### POST/v1/runs/{id}/open

Auth: API key

Reopen a preserved failure as a new, live sandbox — the state the sandbox was in when it broke, not a re-run from the start. It has its own id and its own billing clock, out of what is left of the run's cap.

#### Parameters

idrequiredpath · string

Idempotency-Keyheader · string

Makes a retried create safe: send the same key on every attempt of ONE create and it starts, and bills, once. Kept 24 hours per org. The same key with the same request (method, path and JSON body) answers with the first answer — same status, same ids — marked `Idempotent-Replayed: true`. The same key with a different request is refused with 409 `idempotency_key_reused`. A repeat that arrives while the first is still running waits for its answer, or gets 409 `idempotency_key_in_use` with `Retry-After`. Only an answer that started something is kept: a create refused before anything started leaves the key free. The SDKs send one for every create they make.

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

sandbox_idstring | null

Which captured sandbox; required when the run has more than one capture.

spend_capnumber | null

timeout_msinteger | null

#### Answer 200 · RunOpened · application/json

coderequiredstring

The original's failure code.

committed_secondsrequiredinteger

Billable seconds committed to the new sandbox.

detailrequiredstring

expires_atrequiredstring

When the preserved state expires, RFC 3339.

failed_atrequiredstring

When the original failed, RFC 3339.

max_costrequirednumber

The most the new sandbox may cost, in USD.

okrequiredboolean

opened_fromrequiredstring

The failed sandbox this one was opened from.

outcomerequiredstring

The original's outcome.

ready_msrequirednumber

Milliseconds until it was ready.

run_idrequiredstring

sandbox_idrequiredstring

The new sandbox.

snapshot_idrequiredstring

The preserved state it was opened from.

staterequiredstring

`"ready"`.

timeout_msrequiredinteger

### POST/v1/runs/{id}/replay

Auth: API key

Re-fork the sandboxes whose outcome was an environment failure. Each replay is a new sandbox row with `replay_of` set, billed like any other sandbox; what the failed original is billed is in the run's report (`cost`), and a failure our side shows was ours is credited back.

#### Parameters

idrequiredpath · string

Idempotency-Keyheader · string

Makes a retried create safe: send the same key on every attempt of ONE create and it starts, and bills, once. Kept 24 hours per org. The same key with the same request (method, path and JSON body) answers with the first answer — same status, same ids — marked `Idempotent-Replayed: true`. The same key with a different request is refused with 409 `idempotency_key_reused`. A repeat that arrives while the first is still running waits for its answer, or gets 409 `idempotency_key_in_use` with `Retry-After`. Only an answer that started something is kept: a create refused before anything started leaves the key free. The SDKs send one for every create they make.

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

envmap of string

Values for the environment variables the run's command was started with. A run keeps their names, never their values, so a replay of a command that had any needs every one.

sandbox_idsstring[] | null

The sandboxes to replay; omitted, every one that may be replayed.

#### Answer 200 · RunReplayed · application/json

detailstring | null

Present only when there was nothing to replay, saying so.

okrequiredboolean

replayedrequiredinteger

run_idrequiredstring

sandboxesrequiredReplayRef[]

### GET/v1/runs/{id}/report

Auth: API key

The validity report: every sandbox, its outcome, and whether the failure was the environment's or the task's. Run through your project's secret redactor before it is serialised.

#### Parameters

idrequiredpath · string

#### Answer 200 · Run · application/json

aliasstring | null

costrequiredCost

finished_atstring | null

forkrequiredForkStats

gradeGradeStats | null

The two pass rates and the **gap** between them. Absent when the run was not graded.

labelsmap of string

quoterequiredQuote

A quote, per second: `max_cost = Σ sandbox_count × seconds_per_sandbox × per_second_usd`, where `per_second_usd = vcpus × vcpu_second_usd + mem_gib × gib_second_usd`. The most the run can cost if every sandbox runs its whole timeout; billing is for the seconds actually used.

requestedrequiredRequested

run_idrequiredstring

sandboxesrequiredSandbox[]

schemarequiredstring

snapshot_idrequiredstring

spend_caprequirednumber

started_atrequiredstring

staterequiredRunState

totalsrequiredTotals

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

Auth: API key

Only the sandboxes of a run. `?wait_ms=N` long-polls until nothing is queued any more.

#### Parameters

idrequiredpath · string

wait_msquery · integer

#### Answer 200 · RunSandboxes · application/json

capacityrequiredCapacity

Whether this run's sandboxes can start, in the words a waiting caller needs. Three states: `ok` — nothing is waiting; `arriving` — sandboxes are waiting and should start within `eta_s`; `blocked` — they cannot start now, and the reason is named. A block is a refusal, and it arrives at once rather than after a countdown.

run_idrequiredstring

sandboxesrequiredSandboxView[]

### POST/v1/runs/quote

Auth: API key

Price a run without starting one. No side effects, nothing reserved. Matched ahead of `/v1/runs/:id`, so a run can never be named `quote`.

#### Request body RunQuoteRequest · application/json

countrequiredinteger

1–1000.

preemptibleboolean

snapshotrequiredstring

spend_capnumber | null

tierstring | null

timeout_msinteger | null

#### Answer 200 · RunQuoteView · application/json

billingrequiredstring

`per_second`.

breakdownrequiredQuoteLine[]

countrequiredinteger

credits_availablenumber | null

Trial credits available, in USD; `null` when the organisation is not on a trial.

egressQuoteEgress | null

Data out, priced beside compute: the rate, what the month includes and what is left of it. `max_cost` does not cover it. `null` when the organisation's plan could not be read.

gib_second_usdrequirednumber

granularity_secondsrequiredinteger

max_costrequirednumber

The most the run can cost if every sandbox runs its whole timeout, in USD.

mem_gibrequiredinteger

min_billable_secondsrequiredinteger

per_hour_usdrequirednumber

per_second_usdrequirednumber

preemptiblerequiredboolean

quoterequiredQuote

The same quote, whole — what `POST /v1/runs` and the report echo back.

seconds_per_sandboxrequiredinteger

`ceil(timeout_ms / 1000)`: what one full sandbox may bill.

snapshotrequiredstring

The snapshot as you named it.

snapshot_idstring | null

`null` for a snapshot this service holds no record of.

spend_caprequirednumber

The cap the run would be held to: the one you passed, or the organisation's default.

tierrequiredstring

timeout_msrequiredinteger

vcpu_second_usdrequirednumber

vcpusrequiredinteger

warningsrequiredstring[]

Anything that would make `POST /v1/runs` refuse this, said now.

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