This page needs JavaScript. For agents, the same site as Markdown: https://instabox.sh/llms.txt (below), every page at its URL plus .md.

# InstaBox

> InstaBox gives each agent a Linux machine of its own in the cloud. Start with one command, then read only the page you need.

## Key facts

- API base URL: https://api.instabox.sh. Every body is JSON. Lifecycle calls (create, start, stop, suspend, resume, delete) and the other endpoints that list it need an `Idempotency-Key` header (any unique string); `exec` and Secrets take none. Deleting a machine or snapshot also takes an `X-Confirm-Delete` header, its ID or exact name: any other value is `409 delete_confirmation_required` and nothing is deleted. Send it on every machine delete: API keys created from the rollout on get the same 409 without it.
- Exec: `POST /v1/machines/{id}/exec` takes `cmd` (a shell string, run with `bash -lc`) or `argv` (a program and its arguments, run with no shell), not both: `{"argv": ["printf", "%s|", "a b", "$X"]}` prints `a b|$X|`. Send `Accept: text/event-stream` to get the output as it is written: `stdout`/`stderr` events (`{"data"}`), then an `exit` event with the result (or `error`); the CLI does this with `instabox exec --stream`. Exec returns when the command exits, even if it left a server running in the background; redirect that server’s stdout and stderr to a file (`nohup ./server >server.log 2>&1 &`), since its later writes to exec’s output fail with a broken pipe. Exec output is UTF-8 text: without streaming each stream is cut at 1 MiB (`truncated`), and bytes that are not UTF-8 become U+FFFD (`invalidUtf8`), so read files with `GET /v1/machines/{id}/files/content` or `instabox pull`/`cp`, not `exec cat`; `instabox exec` exits 65 when the command exited 0 but its output was binary.
- Auth: send an API key (`ibk_...`) as `X-API-Key: <key>` or `Authorization: Bearer <key>`, for example `curl -H "X-API-Key: $INSTABOX_API_KEY" https://api.instabox.sh/v1/machines`. Create one in the dashboard (**API keys**) or with `instabox keys create --name N`; the CLI uses `INSTABOX_API_KEY` from the environment. A bad key gets a 401 whose `error.code` says why: `missing_key`, `malformed_key`, `invalid_key`, `expired_key` or `revoked_key`; a key without the scope a route needs gets `403 missing_scope`. Details: https://instabox.sh/docs/api.md
- API key workspace and limits: every key belongs to one workspace and reaches nothing outside it (other workspaces' machines and snapshots are `404`, and what it creates lands in its workspace). `instabox keys create --name N` makes a key of your personal workspace, `--org W` one of workspace `W` (its owner or an admin, signed in); `GET /v1/orgs` (`instabox workspace ls`) called with a key lists only its workspace. To work in another workspace, use a key of that workspace. A key cannot use the sign-in-only routes, which answer `403 permission_denied`: making, listing or revoking API keys, your Vault, GitHub CI installations and jobs, changing billing, creating or deleting workspaces, and sessions. Details: https://instabox.sh/docs/api-keys.md
- Errors: branch on `error.code`, not the message; `retryable` says whether the same request may succeed later, and `retryAfterSeconds` (the `Retry-After` header) how long to wait. Every code with its HTTP status, whether to retry and what to do (the 402 billing codes with the dashboard page and CLI command that fix them): https://instabox.sh/docs/errors.md; each error body's `docs_url` links its entry.
- Quick start: `npx instabox@latest sh` signs in, installs the `instabox` CLI and the instabox agent skills (`~/.claude/skills`, `~/.agents/skills`, `~/.gemini/config/skills`), and starts a machine; `--no-skills` installs no skills. Without a terminal it signs in with `INSTABOX_API_KEY` (no browser, no device code) or exits at once with status 3; `npx instabox@latest skills install -y` installs only the skills, with no sign-in. Or `curl -fsSL https://api.instabox.sh/install.sh | sh` for the CLI alone, which with `INSTABOX_API_KEY` set needs no sign-in. Or call the HTTP API directly with the API key.
- Default template: `agent-browser` (Debian, Docker, Node.js, Bun, Python, Go, Rust, OpenJDK 21, a desktop and Chromium); the free plan creates from `agent-browser`, `android` or `ci` only (or from a snapshot).
- Android: the `android` template (every plan, free included) is `agent-browser` plus Android 14 as a container on the machine's own kernel (no emulator, no nested VM), with adb inside the box (`adb install app.apk`) and the phone on the desktop (Computer tab); pause, idle pause and fork work. No Google Play or Google services; x86_64 only (ARM-only apps need translation, not included). Details: https://instabox.sh/docs/android.md
- Not every common CLI is preinstalled: GNU `time`, `rg` (ripgrep) and `htpasswd` need `sudo apt-get update && sudo apt-get install -y time ripgrep apache2-utils` (the image ships without apt lists, so run `apt-get update` first). `herdr`/`orca` omit Docker.
- Machine: a Firecracker microVM, Debian 13 (trixie) amd64 (`ci`: Ubuntu 24.04), kernel 6.18.54, 4 vCPUs / 8 GiB by default, a 16 GiB root disk (8 GiB on `herdr` and `orca`) and a 20 GiB persistent disk at `/data` (home is `/data/home`). Python 3.13 with `python3 -m venv` and pip on every template but `ci`, which has Python 3.12 with `python3 -m venv` and pip. Per-template specs: the Machine specs table in Limits.
- `/tmp`: RAM tmpfs, not the `/data` disk (~1M inodes). Current templates: login shells set `TMPDIR=/data/tmp` (persistent disk, unused files deleted after 10 days, in snapshots; your own `TMPDIR` is kept) and `/tmp` is capped at a quarter of guest RAM (~1 GiB on 2/4, ~2 GiB on 4/8). Older machines (`echo $TMPDIR` empty): `/tmp` is about half guest RAM (~2 GiB on 2/4, ~4 GiB on 4/8); for big staging set `TMPDIR=$HOME/tmp` (home is `/data/home`; on `agent-browser`, `universal` and `t3` the top of `/data` is the user's too) or remount `/tmp`. Details: Limits → `/tmp` and shared memory.
- Guest defaults: soft `ulimit -n` is 1024; `fs.inotify.max_user_watches` is about 32k–64k (`sysctl -w` raises inotify machine-wide until restart; `ulimit -n` raises nofile for that shell and its children only, so run it in the same exec as the workload). Details: Limits → File watches and open files.
- Snapshots: `create --snapshot` without an explicit size uses the plan `machineSpec` (often 4/8), not the source size — pass `--vcpus`/`--mem-mib`. `rootSizeBytes`/`dataSizeBytes` are logical disk sizes, not stored bytes. Details: Limits → Snapshot create size.
- Swap: every machine gets `/data/swapfile` at its first boot, the size of its memory up to 4 GiB (2/4: 4 GiB), listed in `/etc/fstab` so it stays on across stop and start; it is skipped (and the guest agent logs why) when `/data` would keep under 1 GiB, or a tenth of the disk, free. `swapon`, `swapoff` and `mkswap` are on the user PATH (changing swap takes `sudo`). Removed (`sudo swapoff /data/swapfile && sudo rm /data/swapfile`), it is not made again; `sudo touch /etc/instabox/no-swap` opts out. Details: Limits → Swap.
- OOM: the guest kernel kills the victim (often exit 137); the machine stays running. `GET /v1/machines/{id}` (`instabox get`, `ls --json`) counts the kills in `oomKills` (the newest in `lastOom`), and an exec it killed returns `oomKilled: true` (from the first control release after 2026-10-29.2; before it both are absent). Details: Limits → Out-of-memory (OOM).
- App builds on `universal` / `agent-browser` (and `t3`): `/data` is the user's (`mkdir /data/build` without `sudo`); the Rust toolchain in `/opt/rust` is the user's, so `rustup toolchain install`, `rustup default` and `rustup target add` need no `sudo`, and a rustup of your own in `~/.cargo/bin` takes over the `cargo`/`rustc` wrappers; `zip` and `unzip` are installed; the JDK is OpenJDK 21 (`openjdk-21-jdk-headless`, `JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64`; Debian 13 has no `openjdk-17`). Details: Limits → App builds on `universal` / `agent-browser`.
- Global npm packages: on every template but `ci`, npm's global prefix `/opt/npm` is the machine user's, so `npm install -g` needs no `sudo`; `sudo npm install -g` leaves root-owned files there that break the next install. Details: Limits → Machine specs.
- Upload speed: what a VM sends is capped at ~50 Mbit/s per VM (~6 MB/s), so ~100 MB out (`instabox pull`, a release upload, a public-port response) is ~15–20 s; downloads into the VM are not capped. Not the monthly egress quota. Keep big artifacts on `/data` or in a snapshot. Details: Limits → Outbound bandwidth.
- Sizes (vCPU/GiB): Free 4/8 only; Pro 2/4, 4/8, 8/16; Builder 2/4 up to 16/32; Team 2/4 up to 32/64. `GET /v1/orgs` (`instabox workspace ls --json`) lists each workspace's as `allowedSpecs`. A paid machine moves to another of them while stopped: `instabox resize <machine> --vcpus N --mem-mib M` (on a running or paused one add `--restart`, from outside the machine) or `PATCH /v1/machines/{id}` `{"vcpus": N, "memMiB": M}`, applied at its next start (files stay; a start its host has no room for fails with `no_capacity` and the machine stays stopped at the new size). Another size, or a free machine, is `400 spec_not_allowed` in any state (checked first); a running or paused one is then `409 operation_conflict`: stop it first (a paused machine cannot be stopped: start it, then stop it, which is what `--restart` does).
- Disk: one per machine, `/data`, 20 GiB by default; at create it comes with the size, so leave `persistentDiskGiB` out (another size is `400 spec_not_allowed`; `diskGiB` is the TypeScript SDK option name, and in a REST body it is `400 unknown_field`). A paid machine changes its size with `instabox resize <machine> --disk N [--restart]` or `PATCH /v1/machines/{id}` `{"persistentDiskGiB": N}`: 1-1024 GiB; it grows while running (no restart) or at the next start, and shrinks only while stopped when the data plus 10% (at least 1 GiB) fits (else `409 disk_too_small`); at most 200 GiB on Pro, 500 GiB on Builder, 1024 GiB on Team and Enterprise (`429 quota_exceeded`). The system disk is the template's; only admins grow it (`rootDiskGiB` is `400 spec_not_allowed`). PATCH refuses fields it does not know too, so `diskGiB` there is `400 unknown_field` and nothing changes.
- Plan limits: Free 1 machine, 5 snapshots, 200 GiB stored data, idle pause fixed at 30 min, max run 480 min. Pro 500 machines, 100 running. Builder 1,000 machines, 200 running. Team unlimited machines, 500 running. Paid plans choose the idle time (5-30 min in whole minutes; a part minute, below 5 or above 30 is refused) or turn it off; the free plan refuses another value (https://instabox.sh/docs/machines.md#auto-pause).
- Plans: Free $0, Pro $20/month + usage, Builder $100/month + usage, Team $500/month + usage, Enterprise Custom.
- Usage prices: vCPU $0.004 per vCPU-hour, Memory $0.00225 per GiB-hour, Storage $0.00011 per GiB-hour, Egress $0.02 per GiB. Runtime is billed per second, only while running. Details: https://instabox.sh/docs/pricing.md

## CLI cheat sheet

```
instabox login                                sign in with a device code (or set INSTABOX_API_KEY)
instabox templates                            list templates
instabox create --name N [--template T | --snapshot S]
instabox create --name N --setup-file PATH    then run a script in it (at most 64 KB)
instabox create --devcontainer [PATH|DIR]     from a devcontainer.json: workspace, env, features, lifecycle commands
instabox ls [--json]                          your machines
instabox get <machine> [--json]
instabox exec <machine> -- <cmd...>           run one command; exits with its code
instabox exec --stream <machine> -- <cmd...>  print the output as it is written
instabox exec --stdin <machine> -- <cmd> <f   pipe input up to 5 GiB (a CLI before 2026-10-26: 1 MiB; instabox update)
instabox exec --background <machine> -- <cmd> start a detached job, print its ID
instabox jobs ls|logs|wait|kill <machine>     background jobs (a CLI feature over exec)
instabox agent prompt|events|steer|interrupt|ls <machine>  drive Claude Code or Codex in the machine (a CLI feature over exec)
instabox logs <machine> [-f]                  console log + recent operations; never wakes it
instabox ps <machine> [--all] [--json]        list its processes
instabox history <machine> [--json]           commands run in it through exec, with exit codes (also stopped)
instabox output <machine> [<command-id>]      a past command's stored output (default: the last one)
instabox ssh <machine>                        a shell over SSH
instabox files <machine> [PATH]               list a directory or print a file
instabox cp ./x.tgz <machine>:/data/home/x.tgz copy a file in (or out: cp <machine>:PATH .)
instabox push <machine> ./big.tar            large uploads: push/cp (HTTP API, parallel), not scp/rsync over SSH
instabox suspend|resume <machine>             pause and resume, memory kept
instabox stop|start|rm <machine>
instabox restart <machine>                    power-cycle a hung machine (stop, start), disks kept
instabox resize <machine> --disk N [--restart]  disk full? resize /data to N GB (paid plans; a shrink needs --restart)
instabox resize <machine> --vcpus N --mem-mib M [--restart]  another of your plan's sizes (paid plans; applies while stopped, --restart from outside the machine)
instabox auto-suspend <machine> 10m|0         idle time before pause (0: off, paid plans)
instabox snapshot save <machine> --name N     then create --snapshot N
instabox snapshot import IMAGE --name N      a snapshot from a Docker/OCI image, then create --snapshot N
instabox restore <machine> --snapshot N --yes disks back to snapshot N in place; same ID, name, URLs
instabox fork <machine> [--count N]           copy on its host in seconds (no snapshot)
instabox port publish <machine> <port>        a public HTTPS URL for a port (--private: token-gated link)
instabox port-forward <machine> <port>        a private localhost tunnel until Ctrl-C (or LOCAL:REMOTE)
instabox keys create --name N                 an API key, printed once
instabox usage                                counts and limits
```

Each page below is Markdown. The same page for people is at the URL without .md. Every page in one file: https://instabox.sh/llms-full.txt

## Get started

- [Quick start](https://instabox.sh/docs/start.md): Install the CLI and start your first machine.
- [Concepts](https://instabox.sh/docs/concepts.md): The few words the dashboard, the CLI and the API use.
- [Integrate with the SDK](https://instabox.sh/docs/integrate.md): The calls an app needs: create, pause and resume, delete, a shell, the desktop, and usage.

## Guides

- [Machines](https://instabox.sh/docs/machines.md): Lifecycle, sizes, auto-pause, logs, labels and secrets.
- [Snapshots](https://instabox.sh/docs/snapshots.md): Save a machine once, start new ones from it.
- [Custom images](https://instabox.sh/docs/custom-images.md): Turn a Docker or OCI image into a snapshot, then start machines from it.
- [Connecting over SSH](https://instabox.sh/docs/ssh.md): With the CLI, or one ssh line for any terminal.
- [Public and private ports](https://instabox.sh/docs/ports.md): Give a web server in a machine an HTTPS URL, for anyone or only for people with the link.
- [Desktop: see it and control it](https://instabox.sh/docs/desktop.md): Watch a machine's desktop, let an agent drive it, and, as the machine's creator, share a link to it.
- [Org Secrets](https://instabox.sh/docs/secrets.md): Credentials added to HTTPS headers by the outbound proxy, scoped to your org.
- [Webhooks](https://instabox.sh/docs/webhooks.md): Signed POSTs when a sandbox is ready, pauses, stops, fails or is deleted.
- [Agent sign-up](https://instabox.sh/docs/agent-auth.md): An agent with no browser signs itself up; the account owner approves later with a code.
- [MCP](https://instabox.sh/docs/mcp.md): Sandbox tools for Claude Code, Cursor, Codex, OpenCode and Antigravity over the Model Context Protocol.
- [API keys and SDK](https://instabox.sh/docs/keys-sdk.md): Drive machines from code: TypeScript, HTTP, or the CLI with a key.

## Reference

- [SDK reference](https://instabox.sh/docs/sdk.md): Every class, method and option of @insforge/instabox-sdk.
- [CLI reference](https://instabox.sh/docs/cli.md): Every command. Add --help to any of them for the details.
- [API keys](https://instabox.sh/docs/api-keys.md): How to send a key, make one, what its scopes allow, which workspace it reaches, and what needs a sign-in instead.
- [Idle pause and max-run](https://instabox.sh/docs/idle-suspend.md): When a machine pauses by itself, what wakes it, and the cooldown after a maximum runtime.
- [Pricing](https://instabox.sh/docs/pricing.md): Plans, what each includes, and the unit prices of usage.
- [Billing and usage](https://instabox.sh/docs/billing.md): This month's cost and credit balance: where to read them and how they are computed.
- [Limits](https://instabox.sh/docs/limits.md): What each plan allows, and the machine specs. Account and GET /v1/usage show yours.
- [Errors](https://instabox.sh/docs/errors.md): Every API error code: its HTTP status, whether to retry, when it happens and what to do.

## API reference

- [API overview](https://instabox.sh/docs/api.md): Authentication, operations, idempotency and errors: what every endpoint shares.
- [Machines](https://instabox.sh/docs/api/machines.md): Create, list, change and delete machines.
- [Lifecycle](https://instabox.sh/docs/api/lifecycle.md): Start, stop, pause and resume machines.
- [Commands and files](https://instabox.sh/docs/api/commands.md): Run a command in a machine, and read, upload and download its files.
- [Snapshots](https://instabox.sh/docs/api/snapshots.md): Save a machine, then start new machines from it.
- [Operations](https://instabox.sh/docs/api/operations.md): Follow a change to a machine until it is done.
- [SSH](https://instabox.sh/docs/api/ssh.md): Log in to a machine with ssh or mosh.
- [Public ports](https://instabox.sh/docs/api/ports.md): Give a web server in a machine an HTTPS URL.
- [Secrets](https://instabox.sh/docs/api/secrets.md): Org credentials, sandbox selections and delivery status.
- [Account](https://instabox.sh/docs/api/account.md): Templates, your usage and limits, and who a key belongs to.

## Use cases

- [CI with instabox](https://instabox.sh/docs/ci.md): Send GitHub Actions jobs to instabox with runs-on: instabox-medium, or run a command on instabox from any CI.
- [Android apps](https://instabox.sh/docs/android.md): A machine with Android 14 in it: install and test apps with adb, see the phone on the desktop. Every plan, free included.

## Optional

- [OpenAPI document](https://api.instabox.sh/v1/openapi.json): every endpoint an API key calls, as OpenAPI 3.1 JSON