Sandbox API

Code execution

Run untrusted code in a sandbox via CodeEdit — synchronous, no LLM required.

CodeEdit compiles and runs a small set of files in an isolated sandbox and returns the result on the same HTTP response. There is no job id and nothing to poll: if you need an agent, or a run that outlives one request, use the agent runtime or Harbor instead.

Discover the languages

Language ids come from the platform catalog, not from a fixed list in this page — ask the running deployment rather than guessing, because an id that is not in the catalog is rejected with 400 unknown catalog entry:

curl -sS -H "Authorization: Bearer $SANDBOX_TOKEN" \
  "$SANDBOX_GATEWAY_URL/sandbox/codeedit/v1/languages"

Each entry carries the id to send, the entrypoint_file the runner executes, and the compile and run commands, so you can see exactly what will happen to your code. At the time of writing dev serves python3.12 and cpp20.

The examples below authenticate with a team token, which is what a consumer holds. Against a local stack substitute -H "X-Api-Key: dev-local-key"; see authentication for which credential is which.

Run

files is an object keyed by path, not a list, and one of those paths must be the language's entrypoint_file (main.py for python3.12, main.cpp for cpp20). Send as many files as you need alongside it:

export SANDBOX_GATEWAY_URL="${SANDBOX_GATEWAY_URL:-http://localhost:8780}"

curl -sS -H "Authorization: Bearer $SANDBOX_TOKEN" -H "Content-Type: application/json" \
  -d '{"language":"python3.12","files":{"main.py":"print(2+2)"}}' \
  "$SANDBOX_GATEWAY_URL/sandbox/codeedit/v1/executions"
{"status":"ok","exit_code":0,"stdout":"4","stderr":"","duration_ms":5427,"truncated":false}

status classifies the outcome, so you do not have to infer it from exit_code:

statusMeaning
okCompiled and exited zero
compile_errorNever ran; look at stderr
runtime_errorRan and exited non-zero, with the code in exit_code
tleExceeded wall_time_ms
oomExceeded memory_mb
output_limitProduced more than output_bytes
sandbox_errorThe platform failed, not your code — retryable

Only sandbox_error means the platform is at fault. The rest are verdicts about your program and will not change if you retry them. truncated is true when output was cut at the output_bytes limit, which can accompany any status.

Limits

Every request runs under limits, whether or not you send any. Override them per request with limits. Values outside the accepted range are rejected with 422, so the bounds are part of the contract:

FieldDefaultRangeMeaning
wall_time_ms5000100–30000Run time budget
memory_mb25632–1024Sandbox memory ceiling
pids644–512Max processes, so a fork bomb cannot take the node
output_bytes10485761024–2097152stdout and stderr are truncated past this
filesystem_mb644–512Writable scratch space
-d '{"language":"python3.12","files":{"main.py":"..."},"limits":{"wall_time_ms":20000,"memory_mb":1024}}'

stdin is a string on the request if your program reads input.

wall_time_ms is not yet a tight bound. The sandbox deadline is currently the sum of your limit and a fixed 30-second allowance for scheduling and image pull, so a program that never exits runs for roughly 30 seconds longer than the limit you set. Because that exceeds the load balancer's own 30-second timeout, a program that overruns a short limit surfaces as 502 rather than tle. Do not rely on a small wall_time_ms to bound cost, or to produce a tle verdict, until this is tightened.

Latency, and the cold start

A warm deployment answers a trivial program in roughly 6 seconds end to end. Most of that is sandbox setup rather than your code — CodeEdit runs each execution in a fresh gVisor-isolated pod, which is what makes it safe to hand it untrusted input, and it is not free.

Budget for the cold case separately. When no sandbox-capable node is warm the cluster must add one first, which takes tens of seconds and can exceed the load balancer's 30-second timeout — so the request surfaces as a 502 even though the platform is healthy and the sandbox was starting normally. This is most likely on the first request after an idle period. Treat a 502 on this route as retryable: retry once, and the second attempt lands on the node the first one caused to be created.

If you are dispatching many executions, expect the first to be slow and the rest not to be, and do not put a synchronous execution on a path where a user is waiting on a hard deadline.

Errors

StatusMeaning
400unknown catalog entry — the language id is not in this deployment's catalog
401Missing or invalid credential
422Request shape is wrong — most often files sent as a list instead of an object
429Your project is at its concurrency limit; retry after a moment
502Usually a cold start exceeding the proxy timeout — see above, retry once

Reference: CodeEdit API. See also errors and limits.