Execution & Files
Run commands inside a sandbox and transfer files in and out.
At a glance
- Base URL:
https://api.sb.createos.sh - Auth:
X-Api-Key: <token>header — get a token - Response envelope: JSend —
{"status": "...", "data": ...}
POST /v1/sandboxes/{id}/exec
Run a command inside a running sandbox, either buffered (default) or as a live NDJSON stream.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
stream | boolean | false | When true, response is application/x-ndjson (one ExecStreamEvent per line). Equivalent to setting stream: true in the request body. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
cmd | string | Yes | Program to execute (absolute path or PATH-resolved). |
args | string[] | No | Argument list. |
stdin | string | No | Optional stdin passed to the process. |
env | object | No | Per-exec environment variable overrides. Every key must have been declared in the sandbox's envs at create time — you can override a value, but cannot introduce new keys. Undeclared keys return 400. |
stream | boolean | No | Equivalent to ?stream=true query parameter. |
Note: Background processes must detach (redirect stdio + &) or the exec blocks until they exit.
Buffered mode (default)
Returns after the command exits. Response is a standard JSend success envelope with data.result.
Example request
Bash1curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb_01K.../exec \2 -H "X-Api-Key: $CREATEOS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{"cmd": "/usr/bin/python3", "args": ["-c", "print(1+1)"]}'
Example response
JSON1{2 "status": "success",3 "data": {4 "result": {5 "stdout": "2\n",6 "stderr": "",7 "exit_code": 08 },9 "exec_ms": 124.710 }11}
Streaming mode (?stream=true)
The server emits one JSON object per line over Content-Type: application/x-ndjson (HTTP/1.1 chunked). The terminal frame carries exit_code. Heartbeat lines ({"hb":true}) are emitted every 5 seconds so a dead client is detected and the in-VM command killed within ~5 s of disconnect.
Each line is an ExecStreamEvent:
| Field | Description |
|---|---|
stdout | stdout chunk (string) |
stderr | stderr chunk (string) |
hb | Heartbeat marker; clients should ignore |
exit_code | Terminal frame — last event sent |
error | Agent-level failure (couldn't start command) |
In any one event, exactly one field is meaningful; the rest are zero/absent.
Example request
Bash1curl -X POST "https://api.sb.createos.sh/v1/sandboxes/sb_01K.../exec?stream=true" \2 -H "X-Api-Key: $CREATEOS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{"cmd": "/bin/bash", "args": ["-c", "for i in 1 2 3; do echo $i; sleep 1; done"]}'
Example stream output
{"stdout":"1\n"}
{"hb":true}
{"stdout":"2\n"}
{"stdout":"3\n"}
{"exit_code":0}
Notable errors: 404 sandbox not found or not running, 400 undeclared env key.
PUT /v1/sandboxes/{id}/files
Upload a file into the sandbox.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Absolute path inside the VM. .. is rejected. Parent directories are auto-created. |
Request body
Raw file bytes. Content-Type: application/octet-stream. Maximum size: 500 MiB.
Example request
Bash1curl -X PUT "https://api.sb.createos.sh/v1/sandboxes/sb_01K.../files?path=/workspace/main.py" \2 -H "X-Api-Key: $CREATEOS_API_KEY" \3 -H "Content-Type: application/octet-stream" \4 --data-binary @main.py
Example response
JSON1{2 "status": "success",3 "data": {}4}
Path rules: Path must be absolute (start with /). Relative paths like script.py are rejected with 400.
Notable errors: 400 invalid path or file too large, 404 sandbox not found.
GET /v1/sandboxes/{id}/files
Download a file from the sandbox.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Absolute path inside the VM. .. is rejected. |
Example request
Bash1curl -o result.csv \2 "https://api.sb.createos.sh/v1/sandboxes/sb_01K.../files?path=/workspace/result.csv" \3 -H "X-Api-Key: $CREATEOS_API_KEY"
The response body is the raw file bytes (Content-Type: application/octet-stream).
Notable errors: 404 sandbox or file not found.
Tip: tarball directory transfer
To move a whole directory, tar it on the client, upload the bundle, then unpack inside the sandbox:
Bash1# Upload directory2tar -c mydir | curl -X PUT \3 "https://api.sb.createos.sh/v1/sandboxes/sb_01K.../files?path=/tmp/bundle.tar" \4 -H "X-Api-Key: $CREATEOS_API_KEY" \5 -H "Content-Type: application/octet-stream" \6 --data-binary @-78# Unpack inside sandbox9curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb_01K.../exec \10 -H "X-Api-Key: $CREATEOS_API_KEY" \11 -H "Content-Type: application/json" \12 -d '{"cmd": "tar", "args": ["-C", "/workspace", "-xf", "/tmp/bundle.tar"]}'