Limits and performance
Every hard number the API enforces, in one place — plus an honest account of how long a sandbox takes to start.
At a glance
| Limit | Value | Enforced by |
|---|---|---|
| Requests per minute, per account | 120 | 429 rate_limit_exceeded |
| Sandbox creations per minute, per account | 40 | 429 rate_limit_exceeded |
| Concurrent sandboxes | 20 (provisioning + running) | 429 quota_exceeded |
| Default sandbox lifetime | 15 minutes | automatic teardown |
| Maximum sandbox lifetime | 1440 minutes after creation | hard cap, extension included |
| Command timeout | 60,000 ms default, 600,000 ms maximum | exit_code: 124 |
| Command length | 100,000 characters | 400 invalid_request |
| Request body size | 1 MB | 413 |
| Output captured | 1 MiB per stream | truncated: true |
| Active API keys | 10 per account | dashboard |
| Sandbox list page size | 20 default, 100 maximum | silently clamped |
Rate limits
Two independent windows apply to every API key on an account: 120 requests a minute across all endpoints, and 40 sandbox creations a minute on top of that. Both are fixed 60-second windows counted per account, so extra keys give you no extra headroom.
Every response carries the current state, so you can pace yourself without guessing:
RateLimit-Limit: 120
RateLimit-Remaining: 94
RateLimit-Reset: 37 # seconds until the window resets
Retry-After: 37 # only on a 429
The most common way to hit the general limit is a tight poll loop against a long-running command. Poll every few seconds rather than continuously — see the pattern in running commands.
Concurrency
You can hold 20 sandboxes at once. Sandboxes still provisioning count;
deleted and failed ones do not. Exceeding it is a 429 with
error.type: "quota_exceeded", which — unlike a rate limit — does not clear on its own: you
have to destroy a sandbox first. If your workload is a queue of jobs, cap your worker pool at
20 and make each worker destroy its sandbox in a finally block. Need a
higher ceiling? Ask us.
Timeouts
- Per command:
timeout_ms, default 60,000, maximum 600,000. On expiry the process is killed and you getexit_code: 124with whatever output it had produced. - Per sandbox:
timeout_minutes, default 15, maximum 1440. A sweeper runs every minute and destroys anything past itsexpires_at. - Hard ceiling: 1440 minutes after creation, no matter how often you extend. Work that needs longer must be split across sandboxes, persisting state to storage you control.
Output caps
Each stream is captured up to 1 MiB; beyond that output is dropped and truncated
becomes true. Because the cap is applied as whole chunks arrive, the returned string can
land slightly either side of exactly 1 MiB — treat 1 MiB as the design point, not a byte-exact
guarantee, and check the truncated flag rather than measuring the string. Redirect large
output to a file inside the sandbox and return only the part you need.
Resource limits inside a sandbox
Beyond the vCPU, memory and disk of the size you chose, the sandbox user runs under
per-user limits that stop one runaway process from taking the machine down:
| Limit | Soft | Hard |
|---|---|---|
Processes (nproc) | 512 | 1024 |
Open files (nofile) | 4096 | 8192 |
Single file size (fsize) | 4 GiB | 8 GiB |
Fork bombs hit the process limit rather than the machine. Outbound SMTP (ports 25, 465 and 587) is
blocked as an anti-abuse measure, and a sandbox has no published address, so a server started inside
one is reachable only on its own localhost.
Startup latency
POST /v1/sandboxes is synchronous: it returns only once the machine has booted, finished
its bootstrap and accepted a connection. So the call itself takes as long as the sandbox takes to
start, and how long that is depends on which of two paths it takes.
Warm path — built, not currently in service
The platform can keep a small pool of pre-built machines idling. When a small sandbox is
requested and the pool has a machine available, that machine is claimed and handed over — no boot, no
package installation, just a reset and a health check.
A pooled machine has never belonged to anyone: it is built empty, idles empty, and is destroyed when the sandbox that claimed it is destroyed. It is never returned to the pool and never handed to a second account. The workspace reset before handover is therefore belt-and-braces — it guards against a machine that idled longer than expected or was touched by a failed provision, not against a previous customer, because there has not been one.
The pool is switched off today, so no request takes this path. Every sandbox you create right now is built cold, at the figures in the table below. We would rather say that than let you infer a number from a feature description; when the pool is serving traffic this page will say so and carry its own measurements.
Cold path
If the pool is empty — a burst of requests, or a size other than small, which the pool
does not hold — a machine is created from scratch. That means provisioning, boot, and waiting for the
bootstrap to finish before the sandbox is handed over. It is materially slower than the warm path:
tens of seconds rather than seconds, and longer under load.
What this means for you
- Every size starts the same way, from a prepared image, so a larger sandbox is not slower to get.
- Set a generous client-side HTTP timeout on create — several minutes, not 30 seconds. A client that gives up early leaves a machine running that you are paying for.
- Amortise the cost: create one sandbox and run many commands in it, rather than one sandbox per command.
- Create early. If you know a sandbox will be needed, start provisioning it while you do other work.
- Bursts hurt more than steady load. Ten creations at once will drain the pool and put most of them on the cold path.
Measured numbers
We publish measurements rather than marketing figures. The table below is generated from real provisioning times on this platform; it is updated as the numbers change.
| Path | What happens | Time to ready |
|---|---|---|
| Standard | A machine is created from our prepared image and booted. This is what every request gets today. | ~30–46 s |
| Fallback | Prepared image unavailable; the machine is built from a base image. | ~160 s |
Measured on 22 August 2026, small size, by timing POST /v1/sandboxes from request
to the first successful command. Standard path: machine created at 1.3 s, running at
3.6 s, reachable at 29.7 s, ready at 32.3 s. These are real numbers from this
platform, not a target — they will move as the fleet and regions change, and a single
measurement is not a percentile. Treat sandbox creation as an operation that takes tens of
seconds and design your retries accordingly.
If a create call takes materially longer than the figures above, that is worth telling us about —
include the request_id from the response headers.
Limits that are not published
The platform also enforces a ceiling on how many machines it will run in total. When it is reached,
creation returns 503 with error.type: "capacity_unavailable". This is not a
per-account quota and normally clears within minutes; retry with backoff.