Skip to content
LogoLogo

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.

Use /exec for quick, non-interactive one-shot commands. If a command should be listed, reattached to, sent input after start, signaled, waited on later, stopped as a process tree, or run with terminal semantics, use Managed Processes instead.

Buffered exec output is capped at 1 MiB. If stdout/stderr exceeds the cap, the response includes a truncation notice; use streaming exec for larger output.

Auth required: Yes

Path parameters

ParameterDescription
idSandbox id

Query parameters

ParameterTypeDefaultDescription
streambooleanfalseWhen true, response is application/x-ndjson (one ExecStreamEvent per line). Equivalent to setting stream: true in the request body.

Request body

FieldTypeRequiredDescription
cmdstringYesProgram to execute (absolute path or PATH-resolved).
argsstring[]NoArgument list.
stdinstringNoOptional stdin passed to the process.
envobjectNoPer-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.
streambooleanNoEquivalent to ?stream=true query parameter.

Note: Background processes must detach (redirect stdio + &) or the exec blocks until they exit. For new background work, prefer a managed process so you get a process ID and retained output.


Buffered mode (default)

Returns after the command exits. Response is a standard JSend success envelope with data.result.

Example request

curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb-01K.../exec \
  -H "X-Api-Key: $CREATEOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "/usr/bin/python3", "args": ["-c", "print(1+1)"]}'

Example response

{
  "status": "success",
  "data": {
    "result": {
      "stdout": "2\n",
      "stderr": "",
      "exit_code": 0
    },
    "exec_ms": 124.7
  }
}

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:

FieldDescription
stdoutstdout chunk (string)
stderrstderr chunk (string)
hbHeartbeat marker; clients should ignore
exit_codeTerminal frame, last event sent
errorAgent-level failure (couldn't start command)

In any one event, exactly one field is meaningful; the rest are zero/absent.

Example request

curl -X POST "https://api.sb.createos.sh/v1/sandboxes/sb-01K.../exec?stream=true" \
  -H "X-Api-Key: $CREATEOS_API_KEY" \
  -H "Content-Type: application/json" \
  -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

ParameterDescription
idSandbox id

Query parameters

ParameterTypeRequiredDescription
pathstringYesAbsolute path inside the VM. .. is rejected. Parent directories are auto-created.

Request body

Raw file bytes. Content-Type: application/octet-stream. The API accepts uploads up to 10 GiB per file. For large files, use a streaming client and allow enough time for the transfer; client buffering and gateway timeouts may impose additional constraints.

Example request

curl -X PUT "https://api.sb.createos.sh/v1/sandboxes/sb-01K.../files?path=/workspace/main.py" \
  -H "X-Api-Key: $CREATEOS_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @main.py

Example response

{
  "status": "success",
  "data": {}
}

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

ParameterDescription
idSandbox id

Query parameters

ParameterTypeRequiredDescription
pathstringYesAbsolute path inside the VM. .. is rejected.

Example request

curl -o result.csv \
  "https://api.sb.createos.sh/v1/sandboxes/sb-01K.../files?path=/workspace/result.csv" \
  -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:

# Upload directory
tar -c mydir | curl -X PUT \
  "https://api.sb.createos.sh/v1/sandboxes/sb-01K.../files?path=/tmp/bundle.tar" \
  -H "X-Api-Key: $CREATEOS_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @-
 
# Unpack inside sandbox
curl -X POST https://api.sb.createos.sh/v1/sandboxes/sb-01K.../exec \
  -H "X-Api-Key: $CREATEOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "tar", "args": ["-C", "/workspace", "-xf", "/tmp/bundle.tar"]}'