Sandboxes
Isolated Linux machines to run code, commands and services, billed per second
A sandbox is an isolated Linux (Ubuntu) machine you start through the API or the dashboard, use, and stop when you are done. Use one to run code an agent wrote, build a project, preview a web app, or drive a browser for a few minutes.
The machine is private to that sandbox. It has no access to your Zavu account, to your other sandboxes, or to any secret you did not give it.
Start a sandbox, run code in it and stop it.
Run shell commands, in the foreground or the background, and move files.
Reach a service on a zavu.run URL, connect over SSH, or open its screen.
Copy a sandbox, save its disk, share it, and start with saved variables.
Pricing
Billed from your prepaid balance:
| Size | Machine | Per hour |
|---|---|---|
small | 2 vCPU, 4 GB RAM | $0.0225 |
default | 4 vCPU, 8 GB RAM | $0.045 |
large | 8 vCPU, 16 GB RAM | $0.09 |
- $0.01 per start, each time a sandbox is created, resumed or copied. A sandbox that fails before it ever runs gets it back.
- Machine time per second while the sandbox is
startingorrunning, with a one-minute minimum per run. - A stopped sandbox costs nothing. Its disk is kept 14 days.
- A saved snapshot costs $0.07 per started UTC day while you keep it.
Machine time counts against your monthly spend cap, and appears as Sandboxes in your usage.
Lifecycle
Codestarting ──▶ running ──▶ stopping ──▶ stopped ──▶ (resume) ──▶ starting │ │ │ └──▶ failed ◀┘ └──▶ 14 days later: disk deleted
| Status | Meaning |
|---|---|
starting | Accepted. Commands and file calls made now wait for it to be ready. |
running | Up, and billed. |
stopping | A stop was requested. Billing has already ended. |
stopped | Disk kept until expiresAt. Resume it to continue where you left off. |
failed | Could not start, or failed on its host. See failureReason. |
When it stops
A running sandbox is stopped for you when:
- its
timeoutSecondspasses (default 1 hour, max 24 hours; checked every minute), - your balance, or what is left of your monthly spend cap, no longer covers 15 more minutes of it,
- your team leaves its paid plan.
Send "timeoutSeconds": null on create or resume to turn the first one off: the sandbox runs until you stop it, and the other two still apply. It reads back as null, and it is billed for every second it runs, so stop it when you are done.
Ephemeral sandboxes
Send "ephemeral": true on create for a sandbox whose disk is never saved. Stopping it erases the disk: it reads back as stopped with expiresAt equal to stoppedAt, and resume answers 409 sandbox_expired. It cannot be copied or saved as a snapshot. Read what you need from it before you stop it.
Webhooks
Set up the project webhook and subscribe to these events to know when a sandbox changes state without polling. They matter most for the stops you did not ask for: a timeout, a balance or spend cap that runs out, or the team leaving its paid plan.
| Event | When |
|---|---|
sandbox.running | It finished starting, after a create, resume or copy. Machine time is billed from the start. |
sandbox.stopped | It is down and reads stopped, so it can be resumed. stopReason says why. |
sandbox.failed | It could not start, or failed on its host. See failureReason. |
sandbox_snapshot.ready | A saved snapshot can be started from. |
sandbox_snapshot.failed | A snapshot could not be saved. Its first day is refunded. |
data.sandbox (or data.snapshot) is the object GET returns, read after the change, so you do not need a second call. stopReason is requested (you stopped it), timeout, insufficient_balance, spend_cap_reached, plan or provider, and GET /v1/sandboxes/{sandboxId} returns it too.
await zavu.invitations.webhook.configure({
url: "https://your-app.com/webhooks/zavu",
events: ["sandbox.stopped", "sandbox.failed"],
});
This replaces the events the webhook had: send every event you want to keep. A failed resume is not announced, because the sandbox stays stopped and the call that resumed it already returned the error. Deliveries can repeat or arrive out of order: deduplicate by the event id and trust status over arrival order.
In the dashboard
Agents › Compute sandboxes does everything in these guides on screen: start, stop, resume, copy and delete sandboxes, run commands, expose ports, open the desktop or SSH, and keep saved snapshots, share codes and environments. Anything you do there, you can do through the API, and the other way round.
Limits
| Paid plan | |
|---|---|
| Sandboxes starting or running at once, per team | 10 (403 plan_limit_reached past it) |
| Starts per day, creates, resumes and copies together | 200 (429 daily_limit_exceeded, resets 00:00 UTC) |
timeoutSeconds | 60 to 86,400, or null for no auto-stop |
| File size through the API | 5 MiB |
| Synchronous command | 120 s |
| Exposed ports per sandbox | 20 |
| Saved snapshots per team | 20 |
| Environments per project | 50 |
Errors
| Status | Code | Meaning |
|---|---|---|
402 | paid_plan_required | The team is on Free. |
402 | insufficient_balance | The balance does not cover the $0.01 start and 15 minutes of machine time. |
402 | spend_cap_reached | The monthly spend cap does not leave that much room. |
404 | not_found | The sandbox, snapshot or environment is not in this project, or a share code was revoked. Nothing is charged. |
409 | sandbox_not_running | Commands, files, ports, SSH and the desktop need a starting or running sandbox. |
409 | sandbox_not_ready | Still starting, or the desktop stream is being prepared. Retry in a few seconds. |
409 | port_limit_reached | The sandbox already exposes 20 ports. |
409 | sandbox_not_stopped | Only a stopped sandbox can be resumed. |
409 | sandbox_expired | Its disk was deleted: 14 days after it stopped, or at the stop for an ephemeral sandbox. Create a new one. |
409 | sandbox_ephemeral | An ephemeral sandbox cannot be copied or saved. |
503 | sandbox_unavailable | No capacity right now. Nothing was charged for machine time; retry. |
Every field is in the Sandboxes section of the API reference, starting at Create a sandbox.