Skip to content

Execution API

Run shell commands and scripts inside sandboxes via the Execution API. Execute any process, stream output in real time, and capture exit codes.

MethodPathDescription
POST/v1/sandboxes/:id/executeExecute a command inside a sandbox

Run a command or script inside a running sandbox. The sandbox must be in the running state.

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "echo Hello from sandbox && node --version"
}'
{
"stdout": "Hello from sandbox\nv22.12.0\n",
"stderr": "",
"exitCode": 0,
"durationMs": 245,
"signal": null
}
FieldTypeRequiredDefaultDescription
commandstringYesShell command to execute (bash)
cwdstringNo/workspaceWorking directory for the command
envobjectNo{}Additional environment variables (merged with sandbox env)
timeoutMsintegerNo60000Command timeout in ms (max 300000 = 5 min)
stdinstringNoText to pipe to the command’s stdin
FieldTypeDescription
stdoutstringStandard output from the command
stderrstringStandard error from the command
exitCodeintegerProcess exit code. 0 = success, non-zero = error
durationMsintegerWall-clock execution time in milliseconds
signalstring | nullSignal that killed the process, or null if exited normally

Pass environment variables per execution. These are merged with the sandbox-level env:

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "echo $MY_VAR && echo $CI",
"env": {
"MY_VAR": "custom value",
"CI": "true"
}
}'

Execution-level env vars take precedence over sandbox-level env vars with the same name.

Specify a different working directory:

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "cat package.json",
"cwd": "/workspace/my-project"
}'

Set per-command timeouts. The default is 60 seconds, maximum is 5 minutes:

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "npm run build",
"timeoutMs": 120000
}'

If the command exceeds the timeout, it receives SIGKILL and the response returns:

{
"stdout": "Starting build...\n",
"stderr": "",
"exitCode": null,
"durationMs": 120001,
"signal": "SIGKILL"
}

Pipe input to a command:

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "grep error",
"stdin": "info: starting\ninfo: processing\nerror: something broke\ninfo: done\n"
}'

Response:

{
"stdout": "error: something broke\n",
"stderr": "",
"exitCode": 0,
"durationMs": 12,
"signal": null
}

For long-running commands, stream stdout and stderr in real time using Server-Sent Events (SSE).

Terminal window
curl -X POST https://api.box.runra.dev/v1/sandboxes/sb_x7k2m9p4q1w3v5b8n/execute \
-H "Authorization: Bearer $RUNRA_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"command": "for i in 1 2 3; do echo Line $i; sleep 1; done"
}'
event: stdout
data: Line 1
event: stdout
data: Line 2
event: stdout
data: Line 3
event: done
data: {"exitCode":0,"durationMs":3012,"signal":null}
EventPayloadDescription
stdoutstringA line of stdout output
stderrstringA line of stderr output
doneJSON objectCommand finished (includes exitCode, durationMs, signal)
errorJSON objectExecution error

import { Runra } from "@runra/sandbox";
const client = new Runra();
const sandbox = await client.sandboxes.create({ image: "node:22" });
// Simple execution
const result = await sandbox.exec("npm install && npm run build");
console.log(result.exitCode); // 0
console.log(result.stdout);
// With options
const result = await sandbox.exec("npm test", {
cwd: "/workspace/packages/core",
env: { CI: "true" },
timeoutMs: 120_000,
});
from runra import Runra
client = Runra()
sandbox = client.sandboxes.create(image="node:22")
result = sandbox.exec("ls -la /workspace")
print(result.stdout)
print(f"Exit code: {result.exit_code}")

Exit CodeMeaning
0Success
1127Application-specific error
137Killed by SIGKILL (timeout or OOM)
143Killed by SIGTERM
nullProcess didn’t start or was killed before exit

Always check exitCode rather than relying on stderr being empty. Many tools write to stderr even on success.

const result = await sandbox.exec("npm run lint");
if (result.exitCode !== 0) {
console.error(`Lint failed:\n${result.stderr}`);
}

A single sandbox can handle multiple concurrent executions. The API queues them internally and allows up to 3 concurrent executions per sandbox by default.

// These run concurrently inside the same sandbox
const [result1, result2, result3] = await Promise.all([
sandbox.exec("echo task1 && sleep 2"),
sandbox.exec("echo task2 && sleep 2"),
sandbox.exec("echo task3 && sleep 2"),
]);

If you exceed the concurrency limit, requests return 429 Too Many Requests.


StatusCodeDescription
400INVALID_REQUESTMissing command field
400COMMAND_TOO_LONGCommand exceeds 64KB limit
404SANDBOX_NOT_FOUNDSandbox doesn’t exist
408EXECUTION_TIMEOUTCommand exceeded timeoutMs
409INVALID_STATESandbox is not in running state
429RATE_LIMITEDToo many concurrent executions
502EXECUTION_ERRORInternal sandbox error