Build
Sandboxes
Execute Python and Node.js code in isolated, network-disabled containers with per-second billing.
Sandboxes run short Python or Node.js programs in disposable, network-disabled containers on a dedicated sandbox node. Code never executes in the web or gateway process. Each execution is reserved, billed per second and receipted like an inference request.
Endpoint
Requires an API key with the sandboxes scope. The call is synchronous: it returns when the program exits or times out.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| runtime | string | Required | python or node. |
| code | string | Required | Complete program source, 1–100,000 characters and at most 100 KB as UTF-8. Print results to stdout. |
| timeout_seconds | integer | Optional | 1–30. Defaults to the sandbox configuration's timeout, or the project's maximum (30 s by default). Always capped by the project policy. |
| sandbox_id | string | Optional | A sandbox configuration created in the console. Supplies runtime, timeout, memory and CPU settings; runtime must match. Unknown IDs return 404. |
Programs receive no stdin and cannot open network connections.
Example
curl https://www.hushcompute.xyz/v1/sandbox/executions \
-H "Authorization: Bearer $HUSH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"runtime": "python",
"timeout_seconds": 10,
"code": "import statistics\nprint(statistics.mean([3, 5, 8, 13]))"
}'Response
{
"id": "sbxr_01K58ZY3D5F7H9K2M4P6R8T1V3",
"object": "sandbox.execution",
"status": "completed",
"exit_code": 0,
"stdout": "7.25\n",
"stderr": "",
"stdout_truncated": false,
"stderr_truncated": false,
"duration_ms": 412,
"runner": "docker",
"receipt": {
"id": "rcpt_01K58ZY3E8G1J3L5N7Q9S2U4W6",
"hash": "0x1c7e…9d20",
"signature": "0x44ab…f31c",
"signer": "0x3A4c…91De",
"url": "https://www.hushcompute.xyz/proofs/rcpt_01K58ZY3E8G1J3L5N7Q9S2U4W6"
},
"billing": {
"cost_micro_usd": "40",
"cost_usd": "0.00004",
"fingerprint_salt": "0x8e30…b6a1"
}
}| Field | Type | Description |
|---|---|---|
| id | string | Execution ID (sbxr_…). Recorded as request_id in the receipt. |
| object | string | sandbox.execution |
| status | string | completed, timeout or failed. See Statuses. |
| exit_code | integer | null | The program's exit code; null when it did not exit normally. |
| stdout | string | Standard output, up to the output cap. |
| stderr | string | Standard error, up to the output cap. |
| stdout_truncated | boolean | true if stdout exceeded the cap and was cut at a UTF-8 boundary. |
| stderr_truncated | boolean | true if stderr exceeded the cap. |
| duration_ms | integer | Wall-clock execution time. The billed duration. |
| runner | string | docker in production. See Local development. |
| receipt | object | id, hash, signature, signer, url. Also sent as x-receipt-id. |
| billing | object | cost_micro_usd, cost_usd, and fingerprint_salt for the receipt's fingerprints. |
A non-zero exit code is not an API error: the response is HTTP 200 and the execution is billed and receipted.
Limits
| Resource | Default | Notes |
|---|---|---|
| Timeout | 30 s | Per execution; 1–30 s. The program is stopped when it is reached. |
| Memory | 256 MB | No swap. Configurable per sandbox between 64 and 512 MB, capped by the project policy (256 MB by default). |
| CPU | 0.5 vCPU | Configurable per sandbox, up to 2 vCPU. |
| Processes | 64 | Maximum PIDs inside the container. |
| Output | 64 KB | Per stream: stdout and stderr are capped separately. |
| Workspace | 16 MB | /workspace and /tmp are in-memory, non-executable filesystems. Files larger than 16 MB cannot be written. |
| Open files | 256 | |
| Network | Disabled | No network interface is attached. It cannot be enabled. |
| Code size | 100 KB |
Isolation
Separate execution node
The gateway sends each execution to a sandbox node over an authenticated internal protocol. Requests are signed with HMAC-SHA256 over the method, path, timestamp and body hash; the node rejects timestamps more than 60 seconds off and replayed execution IDs. Responses are signed too, and the gateway verifies the signature before a result is billed or committed to a receipt.
Per-execution container
- A fresh container for every execution, removed afterwards. Nothing persists between executions.
- No network (the container has no network interface).
- Read-only root filesystem; only the in-memory workspace and /tmp are writable, and neither allows executing binaries.
- Runs as an unprivileged, non-root user with all Linux capabilities dropped and privilege escalation disabled.
- cgroup limits on memory (without swap), CPU and process count; file size, open file and core dump limits.
- Code is passed to a fixed launcher over stdin, never through command-line arguments. Runtime images are pinned locally and never pulled at execution time.
- Container logging is disabled, so program output is not persisted by the container runtime.
Pricing
Executions are billed per started second of wall-clock time, with a minimum of 1 second:
| Memory | µUSD per second | USD per hour |
|---|---|---|
| ≤ 256 MB | 40 | $0.144 |
| > 256 MB | 80 | $0.288 |
These are the default rates; operators can set a different per-second base price. Before execution the gateway reserves the cost of the full timeout, and it releases the unused part when the program finishes.
| Example | µUSD | USD |
|---|---|---|
| 300 ms at 256 MB (1 s minimum) | 40 | $0.00004 |
| 2.4 s at 256 MB (3 started seconds) | 120 | $0.00012 |
| 10 s at 512 MB | 800 | $0.0008 |
| Reservation for a 30 s timeout at 256 MB | 1,200 | $0.0012 |
Statuses and receipts
| status | Meaning | Receipt status |
|---|---|---|
| completed | The program ran and exited. Check exit_code for success. | succeeded |
| timeout | The program was stopped at the timeout. | timeout |
| failed | The runtime could not complete the execution. | failed |
Receipts for executions have operation: "sandbox.execute", model: null, the runtime, zero token counts and latency_ms equal to the execution duration. The input fingerprint commits to {"code":…,"runtime":…} and the output fingerprint to {"exit_code":…,"stderr":…,"stdout":…} as returned. See Receipts.
Errors
| Type | HTTP | Cause |
|---|---|---|
| invalid_request | 400 | Invalid runtime, empty or oversized code, timeout out of range, or runtime not matching sandbox_id. |
| insufficient_scope | 403 | The key lacks the sandboxes scope. |
| not_found | 404 | sandbox_id does not exist in this project. |
| budget_exceeded / insufficient_balance | 402 | The timeout reservation does not fit the limits or balance. |
| rate_limit_exceeded | 429 | Key or project requests-per-minute limit reached. |
| sandbox_error | 502 | The sandbox node was unreachable, rejected the request, or returned an unauthenticated or malformed response. |
| service_unavailable | 503 | Sandbox capacity is temporarily exhausted. Retry after 5 seconds. |
When the node cannot run the code (sandbox_error, service_unavailable), the reservation is released and no receipt is issued.
Local development
The runner field states how an execution was handled. Production deployments use docker. Two development-only modes exist:
- dev-process: runs code as a plain host process with no isolation. The sandbox node refuses this runner in production.
- mock: used when no sandbox node is configured on a development deployment. Code is not executed; stdout says so.
Availability
| Capability | Status |
|---|---|
| Python and Node.js executions | Live |
| Sandbox configurations (console) | Live |
| Persistent sandbox sessions | Coming soon |
| Network access | Not supported |