Execution API
Code execution REST API — run commands inside sandboxes with streaming, exit codes, environment variables, working directory, and timeout options
Run shell commands and scripts inside sandboxes via the Execution API. Execute any process, stream output in real time, and capture exit codes.
Endpoint
| Method | Path | Description |
|---|---|---|
POST | /v1/sandboxes/:id/execute | Execute a command inside a sandbox |
POST /v1/sandboxes/:id/execute
Run a command or script inside a running sandbox. The sandbox must be in the running state.
Basic Request
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"
}'
Response — 200 OK
{
"stdout": "Hello from sandbox\nv22.12.0\n",
"stderr": "",
"exitCode": 0,
"durationMs": 245,
"signal": null
}
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
command | string | Yes | — | Shell command to execute (bash) |
cwd | string | No | /workspace | Working directory for the command |
env | object | No | {} | Additional environment variables (merged with sandbox env) |
timeoutMs | integer | No | 60000 | Command timeout in ms (max 300000 = 5 min) |
stdin | string | No | — | Text to pipe to the command's stdin |
Response Fields
| Field | Type | Description |
|---|---|---|
stdout | string | Standard output from the command |
stderr | string | Standard error from the command |
exitCode | integer | Process exit code. 0 = success, non-zero = error |
durationMs | integer | Wall-clock execution time in milliseconds |
signal | string | null | Signal that killed the process, or null if exited normally |
Advanced Usage
Environment Variables
Pass environment variables per execution. These are merged with the sandbox-level env:
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.
Working Directory
Specify a different working directory:
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"
}'
Timeout
Set per-command timeouts. The default is 60 seconds, maximum is 5 minutes:
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"
}
stdin
Pipe input to a command:
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
}
Streaming Output
For long-running commands, stream stdout and stderr in real time using Server-Sent Events (SSE).
Request with Streaming
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"
}'
Streaming Response
event: stdout
data: Line 1
event: stdout
data: Line 2
event: stdout
data: Line 3
event: done
data: {"exitCode":0,"durationMs":3012,"signal":null}
Event Types
| Event | Payload | Description |
|---|---|---|
stdout | string | A line of stdout output |
stderr | string | A line of stderr output |
done | JSON object | Command finished (includes exitCode, durationMs, signal) |
error | JSON object | Execution error |
SDK Usage
TypeScript
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,
});
Python
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 Codes
| Exit Code | Meaning |
|---|---|
0 | Success |
1–127 | Application-specific error |
137 | Killed by SIGKILL (timeout or OOM) |
143 | Killed by SIGTERM |
null | Process 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}`);
}
Concurrency Limits
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.
Common Errors
| Status | Code | Description |
|---|---|---|
400 | INVALID_REQUEST | Missing command field |
400 | COMMAND_TOO_LONG | Command exceeds 64KB limit |
404 | SANDBOX_NOT_FOUND | Sandbox doesn't exist |
408 | EXECUTION_TIMEOUT | Command exceeded timeoutMs |
409 | INVALID_STATE | Sandbox is not in running state |
429 | RATE_LIMITED | Too many concurrent executions |
502 | EXECUTION_ERROR | Internal sandbox error |
Next Steps
- Sandboxes API — manage sandbox lifecycle
- Running Code Guide — execution patterns and best practices
- CLI Reference — run commands via CLI