Sandboxes
Create Sandbox
Base image template. See Available Templates below.
Number of vCPUs (1-8, default: 2).
Memory in MB (128-8192, default: 512).
Disk in GB (1-50, default: 5).
Network access: full, none, or allowlist.
Allowed hosts when network_mode is allowlist.
Environment variables as key-value pairs.
Git repository URL to clone (HTTPS).
PAT or OAuth token for private repositories. GitHub: ghp_..., GitLab: personal access token.
Branch to checkout (default: main/master).
Specific commit SHA to checkout (overrides repo_branch).
Monorepo subdirectory to extract into /workspace.
Maximum spend in USD.
Shell command to run after creation.
Idle timeout in seconds before auto-sleep.
Packages to pre-install (npm/pip packages).
AI agents to install: claude, aider, codex.
curl -X POST https://api.caged.dev/v1/sandboxes \
-H "Authorization: Bearer caged_sk_..." \
-H "Content-Type: application/json" \
-d '{
"template": "node-20",
"cpus": 2,
"memory_mb": 1024,
"repo": "https://github.com/user/project",
"budget": 5.00,
"init_script": "npm install"
}'
Private Repository Example
curl -X POST https://api.caged.dev/v1/sandboxes \
-H "Authorization: Bearer caged_sk_..." \
-H "Content-Type: application/json" \
-d '{
"template": "node-20",
"repo": "https://github.com/your-org/private-repo",
"repo_token": "ghp_xxxxxxxxxxxx",
"repo_branch": "develop",
"agents": ["claude"],
"budget": 10.00
}'
Response 201 Created
{
"id": "cage-a1b2c3d4",
"status": "running",
"template": "node-20",
"ip": "10.0.1.42",
"cpus": 2,
"memory_mb": 1024,
"disk_gb": 5,
"network_mode": "full",
"created_at": "2026-06-08T10:00:00Z"
}
List Sandboxes
curl https://api.caged.dev/v1/sandboxes \
-H "Authorization: Bearer caged_sk_..."
Response 200 OK
[
{
"id": "cage-a1b2c3d4",
"status": "running",
"template": "node-20",
"cpus": 2,
"memory_mb": 1024,
"created_at": "2026-06-08T10:00:00Z"
}
]
Get Sandbox
curl https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4 \
-H "Authorization: Bearer caged_sk_..."
Execute a Command
Run a shell command inside a sandbox and get the output back. Supports pipes, redirects, and environment variables. This is how you interact with sandboxes programmatically — including prompting installed AI agents.
POST /v1/sandboxes/{id}/exec
Shell command to execute. Runs via /bin/sh -c inside the sandbox with the sandbox's environment (including any env vars set at creation).
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/exec \
-H "Authorization: Bearer caged_sk_..." \
-H "Content-Type: application/json" \
-d '{"command": "python --version"}'
Response 200 OK
{
"output": "Python 3.12.3\n",
"exit_code": 0
}
Prompting an agent — if the sandbox was created with "agents": ["claude"], you can prompt Claude Code non-interactively:
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/exec \
-H "Authorization: Bearer caged_sk_..." \
-H "Content-Type: application/json" \
-d '{"command": "cd /workspace && claude -p \"Summarize what this repo does\""}'
Error semantics — the three outcomes are distinguishable:
| Case | exit_code |
error |
Meaning |
|---|---|---|---|
| Success | 0 |
empty | Command ran and succeeded |
| Command failed | non-zero | empty | Command ran; its stderr is in output |
| Infrastructure failure | 1 |
set | Sandbox unreachable, not running, etc. |
A failed command still returns HTTP 200 — the API call succeeded; the command result is data. Exec requests can run for up to 5 minutes, so long agent prompts are fine.
For a fully interactive TTY session (e.g. the Claude Code TUI), use the terminal WebSocket instead: wss://api.caged.dev/v1/sandboxes/{id}/terminal.
Pause Sandbox
Freezes the sandbox in memory. No compute charges while paused. An auto-snapshot is created.
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/pause \
-H "Authorization: Bearer caged_sk_..."
Resume Sandbox
Unfreezes a paused sandbox.
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/resume \
-H "Authorization: Bearer caged_sk_..."
Destroy Sandbox
Permanently destroys a sandbox and all its data.
This action is irreversible. Create a snapshot first if you need to preserve the state.
curl -X DELETE https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4 \
-H "Authorization: Bearer caged_sk_..."
Response 204 No Content
Available Templates
Pre-configured sandbox environments with common runtimes and tools.
JavaScript / TypeScript
| Template | Runtime | Includes |
|---|---|---|
node-22 |
Node.js 22.x LTS | npm, yarn, pnpm, typescript |
node-20 |
Node.js 20.x LTS | npm, yarn, pnpm, typescript |
Python
| Template | Runtime | Includes |
|---|---|---|
python-312 |
Python 3.12 | pip, poetry, virtualenv, black, ruff |
python-311 |
Python 3.11 | pip, poetry, virtualenv, black, ruff |
Base
| Template | Description |
|---|---|
minimal |
Ubuntu 24.04 with SSH, git, curl, build-essential. Install any runtime yourself. |
Desktop
| Template | Description |
|---|---|
desktop |
Full virtual desktop (Xvfb, Openbox, x11vnc, Chromium). For screen-grounded agents. |
Aliases: gui, computer
Using minimal? You can install any runtime manually. The sandbox persists your changes until destroyed.
Screen Endpoints (Desktop Sandboxes)
These endpoints are available for sandboxes created with the desktop template.
Screenshot
Get a screenshot of the virtual desktop.
GET /v1/sandboxes/{id}/screen/screenshot
Response format: base64 (JSON) or omit for raw PNG binary.
# Get base64 JSON
curl "https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/screen/screenshot?format=base64" \
-H "Authorization: Bearer caged_sk_..."
Response 200 OK
{
"image_base64": "iVBORw0KGgo...",
"format": "png"
}
# Get raw PNG
curl "https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/screen/screenshot" \
-H "Authorization: Bearer caged_sk_..." \
-o screenshot.png
Screen WebSocket
Real-time screen interaction via WebSocket.
GET /v1/sandboxes/{id}/screen (WebSocket upgrade)
Connect:
const ws = new WebSocket(
"wss://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/screen",
{ headers: { Authorization: "Bearer caged_sk_..." } }
);
Message Types:
| Type | Direction | Description |
|---|---|---|
screenshot |
send/receive | Request/receive screenshot |
click |
send | Click at coordinates |
type |
send | Type text |
key |
send | Press key |
scroll |
send | Scroll at coordinates |
drag |
send | Drag between coordinates |
launch |
send | Launch application |
info |
send/receive | Get screen info |
Example messages:
// Request screenshot
{"type": "screenshot"}
// Click
{"type": "click", "x": 640, "y": 400, "button": "left"}
// Type text
{"type": "type", "text": "Hello, world!"}
// Press key
{"type": "key", "key": "Return"}
// Scroll down
{"type": "scroll", "x": 640, "y": 400, "direction": "down", "amount": 3}
// Launch app
{"type": "launch", "command": "chromium-browser https://example.com"}
VNC Info
Get VNC connection information for the desktop sandbox.
GET /v1/sandboxes/{id}/screen/vnc
curl "https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/screen/vnc" \
-H "Authorization: Bearer caged_sk_..."
Response 200 OK
{
"sandbox_id": "cage-a1b2c3d4",
"vnc_port": 5900,
"status": "available",
"note": "Use port forwarding to access VNC. The VNC server runs on port 5900 inside the sandbox with no password."
}
Use with port forwarding for external VNC client access.