BOXROUTER_API_KEY set and a client installed, as in the quickstart.
Create It
Ask for what the job needs. This sandbox needs at least 2 CPUs and 2 GiB of memory and may run for 15 minutes. Its label lets you filter on it later.What You Ask for and What BoxRouter Decides
Every field is optional. An empty request gets the standard image, the baseline capabilities (lifecycle, buffered commands and files) and the default lifetime. A capability is something a route may not offer, such as pausing. The fields you set say what the sandbox must have:
Create a sandbox in the API reference lists every field and its limits.
Name a capability that needs no settings in a list, as in
requirements=["pause_resume"]. Give one with settings as an object,
as in {"previews": {"access": "public", "ports": [3000]}}.
BoxRouter decides the rest and records it on the sandbox:
A resource minimum is the smallest size you accept, so you can get more. Read
contract.resources for the size you got.
Credits can pay only for a sandbox of a known size. If you pay with Credits and name no size on a route with no default size, the sandbox gets 2 CPUs and 4 GiB.
BoxRouter never relaxes what you asked for to find a route. If no route can meet the request, the
create request fails with no_eligible_route and nothing is created. Its fix names the nearest change
that would work, and details.nearest lists each such change with the routes it would admit.
A sandbox can use only the capabilities its requirements named. Calling pause on a sandbox created without
pause_resume fails with not_named and leaves the sandbox unchanged. The error’s
details.requirements is the line to add when you create the next one.
A sandbox stays on the provider and account it was created on. Creating the next sandbox
elsewhere does not move this one or its files; a Volume carries files between
sandboxes.
Reuse It from Another Process
Any process with an API key from the same workspace can pick the sandbox up by ID. Enter the printed ID when prompted; this exportsSANDBOX_ID for the examples below.
jq; the HTTP calls reuse API and AUTH from the step that creates the sandbox.
get reads the sandbox’s state without resuming it or extending its lifetime; state timestamps
explain the response. The handle shows the sandbox’s fields as properties, such as box.state, box.lifetime,
and box.cost. They hold the last response; box.refresh() reads the sandbox again.
A command on an ended sandbox fails with sandbox_ended. A second destroy of a destroyed sandbox returns success.
The sandbox list filters by label, state, and provider. It shows
the last recorded state without asking the provider. Fetch one sandbox to request a current observation.
Destroy It
These examples use the sameSANDBOX_ID.
DELETE always answers 202 with the sandbox. Its state is destroyed when the provider confirmed
within the request. It is destroying, with an operation_id, while work remains; BoxRouter finishes the
destroy without you. A repeat DELETE answers 202 with the same sandbox and does not call the
provider a second time.
For a sandbox that lives inside one block of code, let the client destroy it. Use a Python with
block or a TypeScript finally, as in the quickstart. Leaving the block sends
the destroy and updates the handle, so box.state reads the result; it does not prove the destroy finished. If cleanup raises, keep the sandbox ID from
the error and follow Recover from Errors.
Next Steps
How a Sandbox Runs and Ends
Every state, what it keeps and bills, and which clock stops what.
Run Commands
Exit codes, timeouts, and output limits.
How Routing Works
How BoxRouter picks the provider.