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:- API key (recommended for servers/CLI):
- Session JWT (recommended for same-origin apps):
- Browser session cookie (recommended for dashboards):
stateset_sessionis anhttpOnlycookie 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-tokenresponse header on safe requests (GET/HEAD/OPTIONS) and sets a__stateset_csrfcookie. Use that token value for subsequent writes. - Requests authenticated via an
Authorizationheader (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:POST /auth/login
Authenticates and returns a session payload (also setsstateset_session cookie).
Request:
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. RequiresWORKOS_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.comare rejected)organization_id,connection_id,domain_hint,login_hint,screen_hint: WorkOS hints
GET /auth/workos/callback
WorkOS callback. Exchangescode for user identity, then sets a stateset_session cookie and redirects back.
GET /auth/workos/link
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:DELETE /auth/workos/link
Unlinks WorkOS from the authenticated organization. Auth: cookie session (owner). WhenAUDIT_LOGS_ENABLED=true, WorkOS link/unlink operations emit audit actions:
auth.sso.linkauth.sso.unlink
Sandboxes
POST /sandbox/create
Creates a new sandbox. Request:isolationsupportscontainer,gvisor,microvm, andwasm.wasm_networkis valid only whenisolationiswasm.
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:- Set
"stream": true - Response
Content-Type: text/event-stream - Events are emitted as
data: {...}\n\nwithtypevalues: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 asapplication/octet-stream.
REPL Sessions
Interactive Python REPL with persistent session state. Variables and imports survive across execute calls. RequiresREPL_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:POST /sandbox/:id/repl/sessions/:sessionId/stream
Executes code with streaming output via SSE. Request: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. Includesauto_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_hoursis optional and must be an integer between1and168.
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:Idempotency
POST endpoints support safe retries via theIdempotency-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 withIdempotency-Status: replayed. - Body mismatch: If a replay has a different request body hash, the server returns
409 Conflictwith error codeIDEMPOTENCY_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 browserEventSource API does not support custom headers, this endpoint accepts auth via multiple mechanisms:
Authorization: Bearer <jwt>headerAuthorization: ApiKey <key>header?token=<jwt>query parameter?apiKey=<key>query parameter (requires&orgId=<orgId>)- 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-IDrequest header (standard SSE reconnect)?lastEventId=<id>query parameter
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 Requestswith error codeCONCURRENT_LIMIT_EXCEEDED. - With queue mode (
QUEUE_MODE_ENABLED=true):202 Acceptedwith 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. RequiresEGRESS_POLICIES_ENABLED=true.
Policy Model
Domain Matching
- Exact match:
api.github.commatches onlyapi.github.com - Wildcard:
*.npmjs.orgmatchesregistry.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
/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
- When a create/execute request is queued (
202), responses include:X-Stateset-Queue-Status: queuedX-Stateset-Queue-PositionRetry-After
- Queue poll (
GET /requests/:requestId) includesposition,queue_depth, andestimated_wait_seconds. - Queue health (
GET /queue/health) returns per-org queue telemetry for dashboards:queue_depth,processing_count,oldest_queued_age_secondsestimated_wait_seconds,seconds_per_queue_position- rolling-window counts and latency stats (
completed_count,failed_count,expired_count,average_wait_ms,p95_wait_ms)