Skip to main content

API Reference (Node Controller)

Base URL: https://api.sandbox.stateset.com/api/v1 The Node controller is the default deployed by k8s/deployment.yaml.

Authentication

This API supports three auth modes:
  1. API key (recommended for servers/CLI):
  1. Session JWT (recommended for same-origin apps):
  1. Browser session cookie (recommended for dashboards):
  • stateset_session is an httpOnly cookie set by registration/login/invite accept/SSO callback.
  • For state-changing requests authenticated via the session cookie (POST/PUT/PATCH/DELETE), include X-CSRF-Token: <token>.
  • After you have a session cookie, the controller returns an x-csrf-token response header on safe requests (GET/HEAD/OPTIONS) and sets a __stateset_csrf cookie. Use that token value for subsequent writes.
  • Requests authenticated via an Authorization header (API key or Bearer JWT) do not require CSRF.

Errors

Errors are returned as:

Health & Monitoring

GET /health

No auth.

GET /ready

No auth. Returns 503 if not ready.

GET /health/detailed

No auth.

GET /metrics

Internal auth in production (X-Internal-Token or Authorization: Bearer <internal-key>).

Authentication Endpoints

POST /register

Creates an organization + user + API key and sets a session cookie. Request:
Response:

POST /auth/login

Authenticates and returns a session payload (also sets stateset_session cookie). Request:
Response:

POST /auth/logout

Clears the session cookie.

GET /auth/providers

Returns which optional auth providers are configured. Response shape:

GET /auth/session

Returns the current session payload (same shape as /auth/login). Auth: cookie session (stateset_session) or Authorization: Bearer <token>.

GET /auth/workos/authorize

Starts WorkOS AuthKit SSO. Redirects to WorkOS and sets short-lived PKCE cookies. Requires WORKOS_API_KEY, WORKOS_CLIENT_ID, WORKOS_REDIRECT_URI. Query params:
  • return_to: redirect destination after successful login (same-origin relative paths only; protocol-relative values like //example.com are rejected)
  • organization_id, connection_id, domain_hint, login_hint, screen_hint: WorkOS hints

GET /auth/workos/callback

WorkOS callback. Exchanges code for user identity, then sets a stateset_session cookie and redirects back. Returns the current WorkOS linking status for the authenticated organization. Auth: cookie session (admin/owner).

POST /auth/workos/link

Links a WorkOS Organization ID to the authenticated organization. Auth: cookie session (owner). Request:
Unlinks WorkOS from the authenticated organization. Auth: cookie session (owner). When AUDIT_LOGS_ENABLED=true, WorkOS link/unlink operations emit audit actions:
  • auth.sso.link
  • auth.sso.unlink

Sandboxes

POST /sandbox/create

Creates a new sandbox. Request:
Notes:
  • isolation supports container, gvisor, microvm, and wasm.
  • wasm_network is valid only when isolation is wasm.
Response:

GET /sandboxes?limit=20&offset=0

Lists sandboxes for the authenticated organization.

GET /sandbox/:id

Returns sandbox details.

GET /sandbox/:id/status

Returns status + expiry (lightweight).

POST /sandbox/:id/stop

Stops/deletes the sandbox. Alias:
  • DELETE /sandbox/:id

Command Execution

POST /sandbox/:id/execute

Executes a command in the sandbox. Request:
Response (non-streaming):
Streaming (SSE):
  • Set "stream": true
  • Response Content-Type: text/event-stream
  • Events are emitted as data: {...}\n\n with type values: stdout, stderr, exit, done, error

File Operations

File contents are base64 encoded.

POST /sandbox/:id/files

Writes one or more files. Request:

GET /sandbox/:id/files?path=/workspace/main.py

Reads a file (JSON response containing base64 content).

GET /sandbox/:id/files/download?path=/workspace/main.py

Downloads a file as application/octet-stream.

REPL Sessions

Interactive Python REPL with persistent session state. Variables and imports survive across execute calls. Requires REPL_ENABLED=true.

POST /sandbox/:id/repl/sessions

Creates a new REPL session. Request:
language is optional and defaults to python. Response:

GET /sandbox/:id/repl/sessions

Lists REPL sessions for a sandbox. Response:

POST /sandbox/:id/repl/sessions/:sessionId/execute

Executes code in a REPL session. Variables and imports persist across calls. Request:
Response:

POST /sandbox/:id/repl/sessions/:sessionId/stream

Executes code with streaming output via SSE. Request:
Response Content-Type: text/event-stream. Events are emitted as output is produced:

POST /sandbox/:id/repl/sessions/:sessionId/interrupt

Interrupts a running execution in the session. Response:

DELETE /sandbox/:id/repl/sessions/:sessionId

Destroys a REPL session and its kernel. Response:

Session Status Values

Output Types


Templates

GET /templates

Lists templates (summaries).

GET /templates/categories

Lists categories.

GET /templates/:id

Returns a template including file contents.

POST /sandbox/create-from-template

Creates a sandbox based on a template.

Secrets (BYOK)

Secrets are organization-scoped and injected into sandbox pods as environment variables.

POST /secrets

Creates a secret.

GET /secrets

Lists secrets (values are never returned).

PUT /secrets/:name

Updates a secret.

DELETE /secrets/:name

Deletes a secret.

API Keys

GET /api-keys

Lists API keys for the organization.

POST /api-keys

Creates a new API key (the plaintext key is only returned once).

DELETE /api-keys/:id

Revokes an API key.

POST /api-keys/:id/regenerate

Regenerates a key (returns a new plaintext key).

GitHub Integrations

These routes are available when GitHub integration routes are enabled.

GET /github/installations

Lists linked/pending GitHub App installations for the authenticated organization.

POST /github/installations/:id/connect

Links an installation to the authenticated organization.

DELETE /github/installations/:id

Removes a linked installation from the authenticated organization.

GET /github/settings

Returns GitHub automation settings for the organization. Includes auto_pr_comment_on_sandbox to control whether PR-triggered sandboxes post an automatic GitHub comment with dashboard/sandbox details. Includes auto_stop_sandbox_on_pr_close to control whether PR-triggered sandboxes are automatically stopped when the pull request is closed.

PUT /github/settings

Updates GitHub automation settings.

GET /github/events

Returns recent GitHub webhook processing events for the organization.

GET /github/health?window_hours=24

Returns integration health summary (installations, webhook success/failure counts, status, latest event/failure).
  • window_hours is optional and must be an integer between 1 and 168.

Internal Snapshot API (/internal)

These endpoints require internal auth (X-Internal-Token or Authorization: Bearer <internal-token>) in production.

GET /internal/snapshots

List all snapshot profiles. Response:

GET /internal/snapshots/status

Snapshot service health and configuration.

POST /internal/snapshots

Create a snapshot profile. Request example:

GET /internal/snapshots/:profileKey

Get metadata for a single profile.

DELETE /internal/snapshots/:profileKey

Delete a snapshot profile.

POST /internal/snapshots/:profileKey/restore

Restore a snapshot profile into a mock Firecracker runtime.

POST /internal/snapshots/warm

Warm cache, with optional body { "count": 3 }.

POST /internal/snapshots/cleanup

Remove old snapshots by age and/or keep policy. Request example:
Response example:

Idempotency

POST endpoints support safe retries via the Idempotency-Key header. When enabled (IDEMPOTENCY_ENABLED=true, default), the controller caches the response for each unique (orgId, key, route) tuple for 24 hours.

Usage

Behavior

  • First request: Executes normally. Response is stored and returned with Idempotency-Status: stored.
  • Replay: If the same (orgId, key, route) is seen again within 24h, the cached response is returned with Idempotency-Status: replayed.
  • Body mismatch: If a replay has a different request body hash, the server returns 409 Conflict with error code IDEMPOTENCY_KEY_REUSE_MISMATCH.
  • Scope: POST requests only. The header is ignored on GET/PUT/PATCH/DELETE.
  • TTL: 24 hours. After expiry the key can be reused.

Response Headers


Real-time Events (SSE)

GET /events/stream provides a Server-Sent Events stream of sandbox lifecycle events for the authenticated organization.

Authentication

Because the browser EventSource API does not support custom headers, this endpoint accepts auth via multiple mechanisms:
  1. Authorization: Bearer <jwt> header
  2. Authorization: ApiKey <key> header
  3. ?token=<jwt> query parameter
  4. ?apiKey=<key> query parameter (requires &orgId=<orgId>)
  5. Session cookie (stateset_session)

Event Format

Event Types

sandbox.created, sandbox.stopped, sandbox.deleted, artifact.uploaded, checkpoint.created, checkpoint.restored, mcp.tool_called, security.violation, resources.limit_warning

Resumable Streams

On reconnect, include the last received event ID to replay missed events:
  • Last-Event-ID request header (standard SSE reconnect)
  • ?lastEventId=<id> query parameter
The server buffers recent events in memory and replays any events published after the given ID.

Heartbeat

A :heartbeat comment is sent every 20 seconds to keep the connection alive.

Concurrency Budgets & Queue Mode

Each organization has per-plan concurrency budgets for sandboxes and command executions.

Per-Plan Budgets

Limits are configurable via ORG_BUDGET_<PLAN>_MAX_CONCURRENT_SANDBOXES and ORG_BUDGET_<PLAN>_MAX_CONCURRENT_EXECUTES environment variables.

Exceeding Limits

When a request would exceed the budget:
  • Without queue mode: 429 Too Many Requests with error code CONCURRENT_LIMIT_EXCEEDED.
  • With queue mode (QUEUE_MODE_ENABLED=true): 202 Accepted with a queued request ID.

Queued Response Format

Queued Response Headers

Polling

GET /requests/:requestId returns the current status of a queued request, including position, queue_depth, and estimated_wait_seconds. Once completed, response_body and response_status are included.

Queue Health

GET /queue/health returns per-org queue telemetry: queue_depth, processing_count, oldest_queued_age_seconds, estimated_wait_seconds, and rolling-window statistics (completed_count, failed_count, expired_count, average_wait_ms, p95_wait_ms).

Error Codes


Egress Policies

Per-organization outbound network policies. Requires EGRESS_POLICIES_ENABLED=true.

Policy Model

Domain Matching

  • Exact match: api.github.com matches only api.github.com
  • Wildcard: *.npmjs.org matches registry.npmjs.org, www.npmjs.org, etc.

Enforcement Modes (EGRESS_PROXY_MODE)

Error Code


Pagination

List endpoints support standard offset-based pagination.

Query Parameters

Response Format

Endpoints that support pagination: /sandboxes, /artifacts, /checkpoints, /webhooks, /audit, /egress/audit, /requests.

Optional Features

Some routes are only registered when corresponding services are enabled and the database is configured.
  • REPL sessions: /sandbox/:id/repl/sessions, execute, stream, interrupt, destroy (REPL_ENABLED=true)
  • Checkpoints: /sandbox/:id/checkpoints, /checkpoints, …
  • Artifacts: /sandbox/:id/artifacts/upload, /artifacts, multipart uploads at /artifacts/uploads/initiate, /artifacts/uploads/:upload_id/parts/:part_number, /artifacts/uploads/:upload_id/complete, /artifacts/uploads/:upload_id/abort
  • Egress audit: /egress/audit (org query), /internal/egress/audit (proxy/internal ingest)
  • Egress authz adapter: /internal/egress/authorize (proxy authorization check)
  • Egress policy snapshot: /internal/egress/policies (proxy polling/sync)
  • Webhooks: /webhooks, …
  • Tunnels: /sandbox/:id/tunnels, …
  • Audit: /audit, /sandbox/:id/audit/summary
Queue/backpressure notes:
  • When a create/execute request is queued (202), responses include:
    • X-Stateset-Queue-Status: queued
    • X-Stateset-Queue-Position
    • Retry-After
  • Queue poll (GET /requests/:requestId) includes position, queue_depth, and estimated_wait_seconds.
  • Queue health (GET /queue/health) returns per-org queue telemetry for dashboards:
    • queue_depth, processing_count, oldest_queued_age_seconds
    • estimated_wait_seconds, seconds_per_queue_position
    • rolling-window counts and latency stats (completed_count, failed_count, expired_count, average_wait_ms, p95_wait_ms)