Run a command in a sandbox
Runs a command. application/x-ndjson streams one SandboxEvent per line; application/json waits for the exit and answers an ExecResult. The caller names the exec with execId. A request naming an execId the host already knows starts nothing: it replays the exec's output after offset, the seq of the last line already read, and follows the running process. That is how a client reattaches after a lost connection, and every line arrives once. The host keeps an exec's exit code and its most recent 1 MiB of output, the oldest lines dropped first; a reattach from an offset older than that gets a last error line with code OUTPUT_EVICTED. A finished exec is kept while it is one of the sandbox's 16 most recently finished, and after the sandbox ends for up to 10 minutes, sooner when its host holds more than 1,024 ended sandboxes.
Required permission
Requires the sandboxes.exec permission. See Permissions for the roles and API key permissions that include it.
Command line
The orl CLI wraps this endpoint:
Guided workflow: orl sandbox exec
orl sandbox exec <sandbox-id> [--] <command...>apiKeyAuthorizationBearer <token>OpenRelay API key. Send it as Authorization: Bearer or_… (legacy vl_… keys still work).
sandboxId*stringIdempotency-Key?stringMakes a retried create safe. Choose one value per create you mean to make, 1 to 512 bytes (bytes, not characters), such as a UUID, and send it again on every retry of that create. The first request with a key runs, and a 2xx answer is kept for 24 hours: a repeat with the same key and the same body gets that answer back, with the same status and the header Idempotent-Replayed: true, and creates nothing. A batch create compares the body byte for byte; a VM or pod create compares the fields it decodes, so whitespace and key order do not count. A repeat while the first request is still running answers 409; repeat it a second later. The same key with a different body answers 422. An answer other than a 2xx is not kept, so a retry after a 4xx or a 5xx runs again. A 2xx too large to keep holds the key without it: every repeat answers 409 and creates nothing. Keys are scoped to the organization and the operation.
1 <= lengthapplication/json- body
cmd*stringSplit into argv without a shell unless it uses shell syntax, then run under sh -c.
env?cwd?stringtimeoutSeconds?integerexecId?stringThe caller's name for this exec, unique in the sandbox. A request naming an execId the host already knows reattaches to that exec instead of starting one.
offset?integerOn a reattach, the seq of the last line already read. The stream resumes after it.
0 <= value0The command's output and exit, streamed or collected.
- response
type*string"sandbox""stdout""stderr""exit""error"sandbox?text?stringOutput as UTF-8 when it is valid UTF-8.
b64?stringOutput as base64 when it is not.
exitCode?integerseq?integerThe command's event number, 1 up, on every stdout, stderr and exit line. Reattach with the last one read.
int64error?curl -X POST 'https://api.openrelay.inc/v1/sandboxes/string/exec' \ -H 'Content-Type: application/json' \ -d '{ "cmd": "string"}'{ "execId": "string", "exitCode": 0, "stdout": "string", "stderr": "string", "truncated": true, "error": { "error": "string", "code": "string", "permission": "string", "deniedBy": "string", "policies": [ "string" ], "requestId": "string" }}Kill a sandbox DELETE
Answers once the VM is stopped; its memory is released and its usage settled after the answer. Killing a sandbox that has ended answers 410.
Open an interactive terminal in a sandbox GET
Opens an interactive terminal over a WebSocket. Binary frames carry stdin and output; text frames carry resize controls and the exit code. Uses the HTTP/1.1 upgrade; HTTP/2 extended CONNECT (RFC 8441) is not offered. Send {"resize":{"cols":120,"rows":40}} to resize; the last frame received is {"exit":0}.