# Sandbox Quickstart

> Create a managed sandbox, run a command in it, and stop it. A sandbox is a Linux VM the platform runs for you. It connects as a remote, so you run commands on it the same way as on your own machine.

**URL:** https://inference.sh/docs/extend/sandbox-quickstart
**Last updated:** 2026-11-09

---

Create a [managed sandbox](/docs/extend/managed-sandboxes), run a command in it, and stop it. A sandbox is a Linux VM the platform runs for you. It connects as a [remote](/docs/extend/remote), so you run commands on it the same way as on your own machine.

→ [Managed sandboxes](/docs/extend/managed-sandboxes) · [Inside a sandbox](/docs/extend/sandbox-environment) · [Limits and pricing](/docs/extend/sandbox-limits) · [Sandboxes API](/docs/api/rest/sandboxes)

---

## Before you start

- belt **v1.28.21** or later. Check with `belt --version`, update with `belt update`. See [CLI setup](/docs/extend/cli-setup).
- A signed-in session (`belt login`) or `INFERENCE_API_KEY` with the `sandboxes:read`, `sandboxes:write`, `remotes:read` and `remotes:write` scopes. The `standard` preset has all four.
- A purchase in the last 30 days on the workspace that pays. Sandboxes need one (see [Limits and pricing](/docs/extend/sandbox-limits#who-can-create-sandboxes)).

---

## 1. Create a sandbox

```bash
belt sandbox create dev --wait
```

`--wait` returns once the VM is up and its remote is connected. Without it, `create` returns at once and the box boots in the background. The default size is 2 vCPUs, 4096 MiB memory and 10240 MiB disk.

Pick a size with `--vcpus`, `--memory` and `--disk` (MiB):

```bash
belt sandbox create build --vcpus 4 --memory 8192 --disk 20480 --wait
```

## 2. Run commands

```bash
belt sandbox exec dev -- uname -a
belt sandbox exec dev -- bash -c "git clone https://github.com/octocat/Hello-World && ls Hello-World"
belt sandbox exec dev --cwd /tmp --env CI=1 --timeout 600 -- bash -c "echo \$CI && pwd"
```

Output streams as it arrives. belt exits with the command's exit code. Commands run as the `agent` user in `/home/agent`, and `sudo` works without a password. See [Inside a sandbox](/docs/extend/sandbox-environment) for what is installed.

## 3. Check it

```bash
belt sandbox list
belt sandbox get dev --json
```

`status` is `running` while the VM is up. See [Lifecycle](/docs/api/rest/sandboxes#lifecycle) for the other states.

## 4. Stop or delete it

```bash
belt sandbox stop dev --yes      # VM off; disk kept on the engine for the next start
belt sandbox start dev --wait    # boots again, reusing the kept disk when disk_kept is true
belt sandbox delete dev --yes    # removes the sandbox and its remote
```

A running sandbox is billed until you stop it or it stops itself: after 15 minutes with no exec, agent session or `belt sandbox keepalive` on it (the default; set it with `--idle-timeout`, `0` for never). See [Idle auto-stop](/docs/api/rest/sandboxes#idle-auto-stop). Files on the writable disk survive a stop and start on the same engine while the disk is kept; see [Disk](/docs/extend/sandbox-environment#disk).

---

## From scripts and agents

Add `--json` to any `belt sandbox` command for JSON on stdout. Progress and `--wait` updates go to stderr. Add `--no-input` so belt never prompts; `stop`, `delete` and `revoke-grant` then need `--yes`. Exit codes are listed in [Exit codes](/docs/extend/cli-setup#exit-codes).

```bash
id=$(belt sandbox create ci --wait --jq .id)
belt sandbox exec "$id" -- bash -c "make test"
belt sandbox delete "$id" --yes --no-input
```

`get`, `create`, `start` and `stop` print the [sandbox object](/docs/api/rest/sandboxes#sandbox-fields). `list` prints one page with `items`, `next_cursor` and `has_next`.

---

## From the API

The same steps over HTTP. Exec runs on the sandbox's `remote_id` through the [Exec runs API](/docs/api/rest/exec-runs).

```bash
KEY=inf_your_key
API=https://api.inference.sh

# Create
curl -s -X POST $API/sandboxes \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"name":"dev"}'
# → {"id":"...","status":"pending","remote_id":"...", ...}

# Wait until the sandbox is running and its remote is connected
curl -s $API/sandboxes/SANDBOX_ID -H "Authorization: Bearer $KEY"   # status: running
curl -s $API/remotes/REMOTE_ID -H "Authorization: Bearer $KEY"      # status: running

# Run a command
curl -s -X POST $API/remotes/REMOTE_ID/execs \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"command":"bash","args":["-c","uname -a"],"timeout_ms":60000}'
# → {"id":"EXEC_ID","status":"running", ...}

# Read output (data is base64) and the result
curl -s "$API/execs/EXEC_ID/output?after_seq=0" -H "Authorization: Bearer $KEY"
curl -s $API/execs/EXEC_ID -H "Authorization: Bearer $KEY"          # status, exit_code

# Stop, then delete
curl -s -X POST $API/sandboxes/SANDBOX_ID/stop -H "Authorization: Bearer $KEY"
curl -s -X DELETE $API/sandboxes/SANDBOX_ID -H "Authorization: Bearer $KEY"
```

Poll every few seconds; `belt sandbox create --wait` polls every 2 seconds. A sandbox that ends `failed` says why in `status_reason`.

---

## Next

- [Inside a sandbox](/docs/extend/sandbox-environment): installed tools, network, secrets, files, agents in the box
- [Limits and pricing](/docs/extend/sandbox-limits): sizes, plan limits, cost, errors
- [Sandboxes API](/docs/api/rest/sandboxes) · [Exec runs API](/docs/api/rest/exec-runs)
