Sandbox API

Sandboxes

Long-lived workspace / desktop sessions

Long-lived workspace / desktop sessions

Every request needs a credential — see Authentication.

MethodPathSummary
GET/sandbox/sandboxes/v1List Sandboxes
POST/sandbox/sandboxes/v1Create Sandbox
POST/sandbox/sandboxes/v1/_reapReap Sandboxes
DELETE/sandbox/sandboxes/v1/{sandbox_id}Destroy Sandbox
GET/sandbox/sandboxes/v1/{sandbox_id}Get Sandbox
GET/sandbox/sandboxes/v1/{sandbox_id}/artifactsList Sandbox Artifacts
GET/sandbox/sandboxes/v1/{sandbox_id}/artifacts/{capture_id}Get Sandbox Artifact
POST/sandbox/sandboxes/v1/{sandbox_id}/captureCapture Sandbox
GET/sandbox/sandboxes/v1/{sandbox_id}/eventsSSE sandbox lifecycle events
POST/sandbox/sandboxes/v1/{sandbox_id}/execExec Sandbox
DELETE/sandbox/sandboxes/v1/{sandbox_id}/filesDelete File
GET/sandbox/sandboxes/v1/{sandbox_id}/filesGet File
PUT/sandbox/sandboxes/v1/{sandbox_id}/filesPut File
POST/sandbox/sandboxes/v1/{sandbox_id}/startStart Sandbox
POST/sandbox/sandboxes/v1/{sandbox_id}/stopStop Sandbox
POST/sandbox/sandboxes/v1/{sandbox_id}/verifyVerify Sandbox
GET/sandbox/sandboxes/v1/{sandbox_id}/viewerMint viewer URL or proxy the desktop viewer UI
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/actionsUpload the viewer action log (clicks, scrolls, keys, searches)
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/annotationsSubmit a task-ambiguity label for the session
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/recordingsUpload a viewer session screen recording
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/screenshotsUpload a screenshot captured from the viewer canvas
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/startStart Viewer
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/stopStop Viewer
POST/sandbox/sandboxes/v1/{sandbox_id}/viewer/tokenRemint a fresh signed viewer URL (token refresh)
POST/sandbox/sandboxes/v1/{sandbox_id}/workspace/syncSync tenant GCS workspace ↔ guest SandboxWorkspace
POST/sandbox/sandboxes/v1/images/buildBuild-or-resolve a content-addressed desktop image
GET/sandbox/sandboxes/v1/images/build/{build_id}Poll desktop image build status
GET/sandbox/sandboxes/v1/images/build/{build_id}/eventsSSE desktop image build events

Common headers

Accepted on every endpoint on this page.

NameInTypeRequiredDescription
x-correlation-idheaderstringnoEnd-to-end correlation id for this eval run. When set, the gateway and downstream services honor it verbatim in logs, Cloud Trace span attributes, async job payloads, and Langfuse trace.id. When omitted, the gateway generates a ULID and echoes it on the response.
X-Sandbox-Project-Idheaderstring | nullnoProject to bill and rate-limit this request against. Validated against the credential: a project-scoped token may only name its own project, and gets 403 otherwise. Defaults to the token's project when omitted.
X-Sandbox-Tenant-Idheaderstring | nullnoTenant for this request. Must match the credential's tenant when the credential carries one.

Endpoints

List Sandboxes

GET /sandbox/sandboxes/v1

Parameters

NameInTypeRequiredDescription
task_idquerystring | nullno
reuse_fingerprintquerystring | nullnoFilter by create-intent fingerprint (sha256:…).
statusquerystring | nullno

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Create Sandbox

POST /sandbox/sandboxes/v1

Request body

application/json, required — CreateSandboxRequest

FieldTypeRequiredDescription
profilestringnoDefault: "sandboxes-default".
sourceobject | nullno
image_refstring | nullnoImmutable pin from POST …/images/build: OCI repo@sha256:<digest> or gce:projects/{project}/global/images/{name}. Floating tags rejected.
autostop_secnumber | nullnoIdle seconds before the sandbox is stopped (default 1800). Returned on create/GET so clients can show session policy.
ttl_secnumber | nullnoHard max lifetime in seconds before destroy (default 86400). expires_at on the record is created_at + effective ttl.
linked_job_idstring | nullno
task_idstring | nullnoOptional Gen Studio / CTP task id for labels and episode metadata; when omitted, sandbox_id is used.
reusebooleannoWhen true, return an existing non-destroyed sandbox whose create fingerprint matches (owner salt + tenant/project + profile + image_ref + workspace_key + purpose/template labels) instead of provisioning a new session. Default false so pass@k / episode reset stay create-always. Default: false.
reuse_saltstring | nullnoOptional client nonce mixed into the fingerprint salt. Rotate to force a fresh VM while keeping the same task_id. Required for fingerprinting when the caller has no Keycloak owner principal.
labelsobjectnoConsumer tags for analytics (trainer, pass, program, …).

Responses

StatusDescriptionBody
201Successful Responseany
422Validation ErrorHTTPValidationError

Reap Sandboxes

POST /sandbox/sandboxes/v1/_reap

Operator hook: stop/destroy idle sandboxes for this scope.

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Destroy Sandbox

DELETE /sandbox/sandboxes/v1/{sandbox_id}

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
204Successful Response—
422Validation ErrorHTTPValidationError

Get Sandbox

GET /sandbox/sandboxes/v1/{sandbox_id}

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

List Sandbox Artifacts

GET /sandbox/sandboxes/v1/{sandbox_id}/artifacts

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
kindquerystring | nullno
limitqueryintegerno

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Get Sandbox Artifact

GET /sandbox/sandboxes/v1/{sandbox_id}/artifacts/{capture_id}

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
capture_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Capture Sandbox

POST /sandbox/sandboxes/v1/{sandbox_id}/capture

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

SSE sandbox lifecycle events

GET /sandbox/sandboxes/v1/{sandbox_id}/events

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
Last-Event-IDheaderstring | nullno

Responses

StatusDescriptionBody
200Successful Responseany
422Validation ErrorHTTPValidationError

Exec Sandbox

POST /sandbox/sandboxes/v1/{sandbox_id}/exec

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Request body

application/json, required — ExecRequest

FieldTypeRequiredDescription
commandstring[]yes
cwdstring | nullno
timeout_secnumber | nullno
envobject | nullno

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Delete File

DELETE /sandbox/sandboxes/v1/{sandbox_id}/files

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
pathquerystringyes

Responses

StatusDescriptionBody
204Successful Response—
422Validation ErrorHTTPValidationError

Get File

GET /sandbox/sandboxes/v1/{sandbox_id}/files

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
pathquerystringyes

Responses

StatusDescriptionBody
200Successful Responseany
422Validation ErrorHTTPValidationError

Put File

PUT /sandbox/sandboxes/v1/{sandbox_id}/files

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
pathquerystringyes

Request body

application/json, required

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Start Sandbox

POST /sandbox/sandboxes/v1/{sandbox_id}/start

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Stop Sandbox

POST /sandbox/sandboxes/v1/{sandbox_id}/stop

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Verify Sandbox

POST /sandbox/sandboxes/v1/{sandbox_id}/verify

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Request body

application/json, required — VerifyRequest

FieldTypeRequiredDescription
require_verifier_evidencebooleannoDefault: false.

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Mint viewer URL or proxy the desktop viewer UI

GET /sandbox/sandboxes/v1/{sandbox_id}/viewer

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseany
422Validation ErrorHTTPValidationError

Upload the viewer action log (clicks, scrolls, keys, searches)

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/actions

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Request body

application/json, required — ActionLogRequest

FieldTypeRequiredDescription
eventsActionEvent[]yes
recording_idstring | nullnoRecording this log is time-aligned with.

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Submit a task-ambiguity label for the session

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/annotations

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Request body

application/json, required — AmbiguityAnnotation

FieldTypeRequiredDescription
clarity"clear" | "ambiguous"yes
ambiguity_types"intent" | "referential" | "parametric" | "cross_modal"[]noRequired when clarity is 'ambiguous'.
severity"low" | "medium" | "high" | "blocking" | nullno
risk"low" | "medium" | "high" | nullno
feasibility"feasible" | "partially_feasible" | "infeasible" | "unknown" | nullno
alternate_answersstring[]noOther defensible answers a solver could have given.
root_of_confusionstring | nullnoWhat in the task made it ambiguous.
task_promptstring | nullnoInstruction that was annotated.
notesstring | nullno
annotatorstring | nullno
recording_idstring | nullno
actions_idstring | nullno

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Upload a viewer session screen recording

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/recordings

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes
duration_secquerynumber | nullno

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Upload a screenshot captured from the viewer canvas

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/screenshots

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Start Viewer

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/start

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful ResponseViewerDescriptor
422Validation ErrorHTTPValidationError

Stop Viewer

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/stop

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Remint a fresh signed viewer URL (token refresh)

POST /sandbox/sandboxes/v1/{sandbox_id}/viewer/token

Issue a new viewer descriptor when the previous signed token is near expiry.

Requires API key / Keycloak / team token — not an expired viewer cookie. Gen Studio should call this and replace the iframe src with the new url.

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Responses

StatusDescriptionBody
200Successful ResponseViewerDescriptor
422Validation ErrorHTTPValidationError

Sync tenant GCS workspace ↔ guest SandboxWorkspace

POST /sandbox/sandboxes/v1/{sandbox_id}/workspace/sync

Parameters

NameInTypeRequiredDescription
sandbox_idpathstringyes

Request body

application/json, required — WorkspaceSyncRequest

FieldTypeRequiredDescription
direction"pull" | "push"yespull = GCS→guest SandboxWorkspace; push = guest→GCS snapshot.

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

Build-or-resolve a content-addressed desktop image

POST /sandbox/sandboxes/v1/images/build

Publish a curated desktop image via the platform BuildKit pool.

Default (async): 202 + build_id; poll GET …/images/build/&#123;build_id&#125; or stream GET …/images/build/&#123;build_id&#125;/events. Pass sync=true for the legacy hold-open behaviour (gateway long proxy timeout).

Parameters

NameInTypeRequiredDescription
syncquerybooleannoWhen true, hold the connection until BuildKit finishes (legacy).
Idempotency-Keyheaderstring | nullno
X-Sandbox-Job-Idheaderstring | nullno

Request body

application/json, required — BuildDesktopImageRequest

FieldTypeRequiredDescription
profilestringnoDefault: "desktop-ubuntu".
appsstring[] | nullnoCatalog desktop_app ids (e.g. chrome). Mutually exclusive with bundle.
bundlestring | nullnoCatalog desktop_app_bundle id (e.g. osworld). Mutually exclusive with apps.
datapoint_idstring | nullnoOptional builder tag prefix; defaults to sandboxes-{profile}.

Responses

StatusDescriptionBody
200Successful Responseany
422Validation ErrorHTTPValidationError

Poll desktop image build status

GET /sandbox/sandboxes/v1/images/build/{build_id}

Parameters

NameInTypeRequiredDescription
build_idpathstringyes

Responses

StatusDescriptionBody
200Successful Responseobject
422Validation ErrorHTTPValidationError

SSE desktop image build events

GET /sandbox/sandboxes/v1/images/build/{build_id}/events

Parameters

NameInTypeRequiredDescription
build_idpathstringyes
Last-Event-IDheaderstring | nullno

Responses

StatusDescriptionBody
200Successful Responseany
422Validation ErrorHTTPValidationError

Schemas

The object shapes referenced above.

ActionEvent

One operator interaction inside the viewer.

FieldTypeRequiredDescription
atnumberyesMilliseconds since the recording started.
typestringyesclick, scroll, key, search, screenshot…
xinteger | nullno
yinteger | nullno
delta_xnumber | nullno
delta_ynumber | nullno
keystring | nullno
textstring | nullno
detailobject | nullno

ActionLogRequest

FieldTypeRequiredDescription
eventsActionEvent[]yes
recording_idstring | nullnoRecording this log is time-aligned with.

AmbiguityAnnotation

Task-ambiguity label for a session, with its evidence references.

FieldTypeRequiredDescription
clarity"clear" | "ambiguous"yes
ambiguity_types"intent" | "referential" | "parametric" | "cross_modal"[]noRequired when clarity is 'ambiguous'.
severity"low" | "medium" | "high" | "blocking" | nullno
risk"low" | "medium" | "high" | nullno
feasibility"feasible" | "partially_feasible" | "infeasible" | "unknown" | nullno
alternate_answersstring[]noOther defensible answers a solver could have given.
root_of_confusionstring | nullnoWhat in the task made it ambiguous.
task_promptstring | nullnoInstruction that was annotated.
notesstring | nullno
annotatorstring | nullno
recording_idstring | nullno
actions_idstring | nullno

BuildDesktopImageRequest

Build-or-resolve a content-addressed desktop image from curated catalog apps.

FieldTypeRequiredDescription
profilestringnoDefault: "desktop-ubuntu".
appsstring[] | nullnoCatalog desktop_app ids (e.g. chrome). Mutually exclusive with bundle.
bundlestring | nullnoCatalog desktop_app_bundle id (e.g. osworld). Mutually exclusive with apps.
datapoint_idstring | nullnoOptional builder tag prefix; defaults to sandboxes-{profile}.

CreateSandboxRequest

FieldTypeRequiredDescription
profilestringnoDefault: "sandboxes-default".
sourceobject | nullno
image_refstring | nullnoImmutable pin from POST …/images/build: OCI repo@sha256:<digest> or gce:projects/{project}/global/images/{name}. Floating tags rejected.
autostop_secnumber | nullnoIdle seconds before the sandbox is stopped (default 1800). Returned on create/GET so clients can show session policy.
ttl_secnumber | nullnoHard max lifetime in seconds before destroy (default 86400). expires_at on the record is created_at + effective ttl.
linked_job_idstring | nullno
task_idstring | nullnoOptional Gen Studio / CTP task id for labels and episode metadata; when omitted, sandbox_id is used.
reusebooleannoWhen true, return an existing non-destroyed sandbox whose create fingerprint matches (owner salt + tenant/project + profile + image_ref + workspace_key + purpose/template labels) instead of provisioning a new session. Default false so pass@k / episode reset stay create-always. Default: false.
reuse_saltstring | nullnoOptional client nonce mixed into the fingerprint salt. Rotate to force a fresh VM while keeping the same task_id. Required for fingerprinting when the caller has no Keycloak owner principal.
labelsobjectnoConsumer tags for analytics (trainer, pass, program, …).

ExecRequest

FieldTypeRequiredDescription
commandstring[]yes
cwdstring | nullno
timeout_secnumber | nullno
envobject | nullno

HTTPValidationError

FieldTypeRequiredDescription
detailValidationError[]no

ValidationError

FieldTypeRequiredDescription
locstring | integer[]yes
msgstringyes
typestringyes
inputanyno
ctxobjectno

VerifyRequest

FieldTypeRequiredDescription
require_verifier_evidencebooleannoDefault: false.

ViewerDescriptor

Signed desktop viewer entry returned on running desktop/ide sandboxes.

FieldTypeRequiredDescription
urlstringyesGateway URL to open the viewer (includes signed token).
mode"novnc" | "guacamole" | "provider" | "selkies-ws" | "openvscode"yesIntegration mode for the external viewer_ui library.
embedstringnoDefault: "iframe".
input_enabledbooleanyesFalse while the sandbox is not in running status.
resolutioninteger[]no
expires_atintegeryesUnix epoch seconds when the signed viewer token in url expires. Remint via POST /v1/{sandbox_id}/viewer/token before this time.
guest_usernamestring | nullnoGuest OS login name when the provider exposes identity.
guest_hostnamestring | nullnoGuest OS hostname shown in the desktop shell.
guest_homestring | nullnoGuest home directory.
workspace_mountstring | nullnoGuest path for tenant workspace files (SandboxWorkspace).
stream_urlstring | nullnoOptional C1 gateway WebSocket path for pixels/input (/sandbox/stream/v1/{id}/websockify?ticket=…).

WorkspaceSyncRequest

FieldTypeRequiredDescription
direction"pull" | "push"yespull = GCS→guest SandboxWorkspace; push = guest→GCS snapshot.

Machine-readable spec: OpenAPI YAML.

On this page

Common headersEndpointsList SandboxesParametersResponsesCreate SandboxRequest bodyResponsesReap SandboxesResponsesDestroy SandboxParametersResponsesGet SandboxParametersResponsesList Sandbox ArtifactsParametersResponsesGet Sandbox ArtifactParametersResponsesCapture SandboxParametersResponsesSSE sandbox lifecycle eventsParametersResponsesExec SandboxParametersRequest bodyResponsesDelete FileParametersResponsesGet FileParametersResponsesPut FileParametersRequest bodyResponsesStart SandboxParametersResponsesStop SandboxParametersResponsesVerify SandboxParametersRequest bodyResponsesMint viewer URL or proxy the desktop viewer UIParametersResponsesUpload the viewer action log (clicks, scrolls, keys, searches)ParametersRequest bodyResponsesSubmit a task-ambiguity label for the sessionParametersRequest bodyResponsesUpload a viewer session screen recordingParametersResponsesUpload a screenshot captured from the viewer canvasParametersResponsesStart ViewerParametersResponsesStop ViewerParametersResponsesRemint a fresh signed viewer URL (token refresh)ParametersResponsesSync tenant GCS workspace ↔ guest SandboxWorkspaceParametersRequest bodyResponsesBuild-or-resolve a content-addressed desktop imageParametersRequest bodyResponsesPoll desktop image build statusParametersResponsesSSE desktop image build eventsParametersResponsesSchemasActionEventActionLogRequestAmbiguityAnnotationBuildDesktopImageRequestCreateSandboxRequestExecRequestHTTPValidationErrorValidationErrorVerifyRequestViewerDescriptorWorkspaceSyncRequest