API Reference
ConnectRPC over HTTP/1.1 with JSON. All endpoints require a Bearer token unless noted.
Base URL:
Auth:
https://api.upstream.buildAuth:
Authorization: Bearer sk-...
Sandbox lifecycle
CreateSandbox
Provision a Firecracker microVM.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/CreateSandbox \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"template": "claude-code", "context_id": "my-project"}'
| Field | Type | Description |
|---|---|---|
template | string | Template name: claude-code, python, nodejs |
context_id | string | Customer context ID for persistence across sessions |
env | map<string,string> | Environment variables to inject |
cwd | string | Working directory inside the sandbox |
client_public_key | string | X25519 public key for E2E encryption (base64) |
Response:
{
"sandbox_id": "sb-a1b2c3d4",
"status": "creating",
"server_public_key": "base64...",
"auth_token": "hmac-token..."
}
GetSandbox
Check sandbox status.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/GetSandbox \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4"}'
Response:
{
"sandbox_id": "sb-a1b2c3d4",
"status": "ready",
"template": "claude-code",
"vcpu": 2,
"memory_mib": 2048,
"created_at": "2026-04-03T10:00:00Z"
}
Status values: creating, ready, running, stopped, failed.
ListSandboxes
List all active sandboxes for the current tenant.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/ListSandboxes \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{}'
DeleteSandbox
Destroy a sandbox and release resources.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/DeleteSandbox \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4"}'
Execution
Exec
Execute a command and wait for the result.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/Exec \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4", "command": ["python", "-c", "print(42)"]}'
| Field | Type | Description |
|---|---|---|
sandbox_id | string | Target sandbox |
command | string[] | Command and arguments |
working_dir | string | Working directory (default: /workspace) |
env | map<string,string> | Additional environment variables |
Response:
{
"exit_code": 0,
"stdout": "NDI=",
"stderr": "",
"duration_ms": 42
}
Note:
stdout and stderr are base64-encoded bytes in the ConnectRPC response. The Python SDK decodes them automatically.
ExecStream
Execute a command with streaming output. Returns a server-sent event stream.
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/ExecStream \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4", "command": ["tail", "-f", "/var/log/syslog"]}'
Each event contains one of: stdout (bytes), stderr (bytes), or exit_code (int32).
Filesystem
ReadFile
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/ReadFile \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4", "path": "/workspace/main.py"}'
WriteFile
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/WriteFile \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4", "path": "/workspace/main.py", "content": "cHJpbnQoJ2hlbGxvJyk="}'
Content is base64-encoded bytes.
ListFiles
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/ListFiles \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"sandbox_id": "sb-a1b2c3d4", "path": "/workspace"}'
Response:
{
"entries": [
{ "name": "main.py", "is_dir": false, "size": 1024 },
{ "name": "src", "is_dir": true, "size": 0 }
]
}
Usage & billing
GetUsage
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/GetUsage \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"since": "2026-04-01T00:00:00Z", "until": "2026-04-03T23:59:59Z"}'
Response:
{
"total_sessions": 142,
"total_vcpu_seconds": 86400.5,
"total_gib_seconds": 172800.0,
"total_duration_seconds": 43200.25
}
Templates
ListTemplates
$ curl -X POST https://api.upstream.build/upstream.platform.v1.Platform/ListTemplates \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{}'
Response:
{
"templates": [
{ "name": "claude-code", "default_vcpu": 2, "default_memory_mib": 2048 },
{ "name": "python", "default_vcpu": 2, "default_memory_mib": 512 },
{ "name": "nodejs", "default_vcpu": 2, "default_memory_mib": 512 }
]
}
REST endpoints
The following REST endpoints are also available alongside ConnectRPC.
Health & readiness
$ curl https://api.upstream.build/healthz
{"status": "ok"}
$ curl https://api.upstream.build/readyz
{"status": "ready"}
No authentication required.
API keys
# List keys (metadata only)
$ curl https://api.upstream.build/v1/keys \
-H "Authorization: Bearer sk-..."
# Create a new key
$ curl -X POST https://api.upstream.build/v1/keys \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"name": "ci-pipeline"}'
# Revoke a key
$ curl -X DELETE https://api.upstream.build/v1/keys/42 \
-H "Authorization: Bearer sk-..."
Error codes
| Code | HTTP | Description |
|---|---|---|
AUTH_REQUIRED | 401 | No authorization header |
AUTH_INVALID | 403 | Invalid or revoked API key |
RATE_LIMITED | 429 | Too many requests. Check Retry-After header. |
QUOTA_EXCEEDED | 429 | Monthly compute quota reached |
SANDBOX_NOT_FOUND | 404 | Sandbox ID does not exist or was destroyed |
INVALID_PIPELINE | 400 | Markdown pipeline parse error |
NO_STEPS | 400 | Pipeline contains no executable code blocks |
INTERNAL_ERROR | 500 | Server error. Retry with backoff. |