# Running commands

> Run shell commands in a sandbox, synchronously or asynchronously, poll for long-running output, and use the interactive terminal.

> **Want a live shell instead?** The dashboard's sandbox page has a full **interactive
> terminal** (a real PTY - run `top`, `vim`, REPLs, watch live output). Programmatically, it's
> the WebSocket endpoint `WS /v1/sandboxes/{id}/terminal` (see the
> [API reference](./api.md)). The command API below is best for scripted, one-shot execution.

Run a shell command inside a sandbox. Commands execute from the working directory
(`/workspace` by default) and return stdout, stderr, and an exit code.

```http
POST /v1/sandboxes/{sandbox_id}/commands
```

Request fields:

| Field | Default | Notes |
|-------|---------|-------|
| `command` | - (required) | The shell command to run. |
| `working_directory` | `/workspace` | Where to run it. |
| `timeout_seconds` | plan default | Capped by your [plan](./plans-and-limits.md). |
| `async` (alias `background`) | `false` | Run without blocking - see below. |

## Synchronous (default)

Blocks until the command finishes, then returns the result (`201`):

```bash
curl -X POST https://flaxcloud.com/v1/sandboxes/$SID/commands \
  -H "Authorization: Bearer $FLAX_API_KEY" -H "Content-Type: application/json" \
  -d '{"command":"pip install requests && python script.py"}'
```

```json
{ "id": "cmd_…", "status": "completed", "exit_code": 0,
  "stdout": "…", "stderr": "", "timed_out": false }
```

Use this for quick work that finishes within the timeout. If it exceeds the timeout the
command is killed and `status` is `timeout`.

## Asynchronous (long-running)

For dev servers, build steps, test suites, or AI agents that run longer than a request should
wait, set `"async": true`. The call returns **immediately** (`202`) with a `running` command;
you then **poll** for the result.

```bash
# start it
curl -X POST https://flaxcloud.com/v1/sandboxes/$SID/commands \
  -H "Authorization: Bearer $FLAX_API_KEY" -H "Content-Type: application/json" \
  -d '{"command":"npm run dev","async":true}'
# → 202 { "id": "cmd_…", "status": "running", ... }

# poll for status/output
curl https://flaxcloud.com/v1/commands/$CMD_ID -H "Authorization: Bearer $FLAX_API_KEY"
```

`status` progresses to `completed`, `failed`, or `timeout`; `stdout`/`stderr` accumulate as
the command runs. A sandbox with a running async command is protected from idle reclaim until
it finishes.

> Tip: starting a server with an async command is the clean way to keep it alive for a
> [preview](./previews.md). (From the dashboard's synchronous command box you can background
> it manually with `nohup … &`, but async is preferred.)

## Fetch a command

```http
GET /v1/commands/{command_id}
```

Returns the command's current status and output. Useful for both async polling and looking up
past runs.
