# First sandbox in 5 minutes

> Create your first Flax Cloud sandbox, run code, move files, open a preview, connect a browser over CDP, snapshot it, and clean up.

This guide gets you from a new account to a useful sandbox workflow: create a sandbox, run a
command, upload and list files, open a preview URL, create a browser sandbox with a CDP URL,
capture a snapshot, and clean up. Use the dashboard for the first pass, then copy the SDK, CLI, or
REST example that matches your workflow.

## 1. Sign in and create a key

Open **https://flaxcloud.com/app/** and sign in. New accounts start on the **Free** plan.

In the dashboard, go to **API Keys -> Create key**. The key (`flax_live_...`) is shown **once** -
copy it somewhere safe. Only a hash is stored, so if you lose it you create a new one.

Set it locally:

```bash
export FLAX_API_KEY=flax_live_xxxxx
# Optional, only needed for local/self-hosted testing:
export FLAX_BASE_URL=https://flaxcloud.com
```

SDKs and the CLI read `FLAX_API_KEY`. The REST API expects the same key as a bearer token:

```bash
curl https://flaxcloud.com/v1/me \
  -H "Authorization: Bearer $FLAX_API_KEY"
```

## 2. Create and run your first sandbox

A sandbox is an isolated Linux workspace. Pick a [template](./concepts.md#templates), usually
`python`, `node`, or `blank`. Free accounts can create `1 GB` sandboxes. Pro can create `2 GB`,
Builder `4 GB`, and Team `8 GB`.

### Python SDK

```bash
pip install flaxcloud
```

```python
from flaxcloud import FlaxClient

flax = FlaxClient()  # reads FLAX_API_KEY and optional FLAX_BASE_URL

with flax.create_sandbox(template="python", name="first-run", memory_mb=512) as sb:
    result = sb.run("python3 -c 'print(6 * 7)'")
    print(result.stdout)  # 42
```

### JavaScript / TypeScript SDK

```bash
npm install @flaxcloud/sdk
```

```ts
import { FlaxClient } from "@flaxcloud/sdk";

const flax = new FlaxClient(); // reads FLAX_API_KEY and optional FLAX_BASE_URL

const sb = await flax.createSandbox({ template: "python", name: "first-run", memoryMb: 512 });
try {
  const result = await sb.run("python3 -c 'print(6 * 7)'");
  console.log(result.stdout); // 42
} finally {
  await sb.destroy();
}
```

### REST API

```bash
SID=$(
  curl -s -X POST https://flaxcloud.com/v1/sandboxes \
    -H "Authorization: Bearer $FLAX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"template":"python","memory_mb":512,"metadata":{"name":"first-run"}}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])'
)

curl -X POST "https://flaxcloud.com/v1/sandboxes/$SID/commands" \
  -H "Authorization: Bearer $FLAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command":"python3 -c \"print(6 * 7)\""}'
```

### CLI

```bash
pip install flaxcloud
flax login
SID=$(flax sandbox create --template python --memory 512 --name first-run)
flax run "$SID" "python3 -c 'print(6 * 7)'"
```

## 3. Upload and list files

```python
sb = flax.create_sandbox(template="python")
sb.upload("/workspace/app.py", "print('hello from /workspace')\n")
print(sb.run("python3 /workspace/app.py").stdout)
for entry in sb.list_files("/workspace"):
    print(entry.name, entry.size_bytes)
sb.destroy()
```

```ts
const sb = await flax.createSandbox({ template: "python" });
await sb.upload("/workspace/app.py", "print('hello from /workspace')\n");
console.log((await sb.run("python3 /workspace/app.py")).stdout);
console.log(await sb.listFiles("/workspace"));
await sb.destroy();
```

```bash
printf "print('hello from /workspace')\n" > app.py
flax cp ./app.py "$SID":/workspace/app.py
flax ls "$SID" /workspace
```

## 4. Open a preview URL

Start a web server bound to `0.0.0.0`, then create a shareable preview link. Use a startup command
for servers that should come back automatically after stop/resume.

```python
sb = flax.create_sandbox(
    template="python",
    startup_command="python3 -m http.server 8000 --bind 0.0.0.0",
)
sb.run_startup()
print(sb.create_preview_link(8000).url)
```

```ts
const sb = await flax.createSandbox({
  template: "python",
  startupCommand: "python3 -m http.server 8000 --bind 0.0.0.0",
});
await sb.runStartup();
console.log((await sb.createPreviewLink(8000)).url);
```

```bash
flax startup "$SID" --set "python3 -m http.server 8000 --bind 0.0.0.0" --run
flax preview "$SID" 8000
```

Private owner-only previews are also available at
`https://flaxcloud.com/v1/sandboxes/$SID/preview/8000/` while authenticated. See
[Previews](./previews.md).

## 5. Create a browser sandbox and CDP URL

Browser sandboxes run Chromium inside the sandbox. The CDP URL is short-lived and secret: mint a
fresh one per automation run and keep it server-side.

```python
browser = flax.create_sandbox(capabilities=["browser"], memory_mb=512)
browser.browser.start()
cdp_url = browser.browser.get_cdp_url()
print(cdp_url)
browser.destroy()
```

```ts
const browser = await flax.createSandbox({ capabilities: ["browser"], memoryMb: 512 });
await browser.browser.start();
console.log(await browser.browser.getCdpUrl());
await browser.destroy();
```

```bash
BROWSER_ID=$(flax sandbox create --browser --memory 512)
flax browser start "$BROWSER_ID"
flax browser cdp-url "$BROWSER_ID"
flax sandbox rm "$BROWSER_ID"
```

See [Browser automation](./browser.md) for Playwright and Puppeteer examples.

## 6. Snapshot a prepared sandbox

Snapshots capture `/workspace` and sandbox configuration, not running processes or RAM. Use them
for prepared agent bases, dependency installs, or repeatable test environments.

```python
sb = flax.create_sandbox(template="python")
sb.upload("/workspace/app.py", "print('ready')\n")
snap = sb.create_snapshot("agent-base")
sb.destroy()

restored = flax.create_sandbox(snapshot_id=snap.id)
print(restored.read_text("/workspace/app.py"))
restored.destroy()
flax.delete_snapshot(snap.id)
```

```ts
const sb = await flax.createSandbox({ template: "python" });
await sb.upload("/workspace/app.py", "print('ready')\n");
const snap = await sb.createSnapshot("agent-base");
await sb.destroy();

const restored = await flax.createSandbox({ snapshotId: snap.id });
console.log(await restored.readText("/workspace/app.py"));
await restored.destroy();
await flax.deleteSnapshot(snap.id);
```

```bash
flax snapshot create "$SID" agent-base
flax snapshot ls
flax snapshot rm snap_abc123
```

See [Snapshots](./snapshots.md).

## 7. Clean up

Sandboxes you stop are persisted and can be resumed; destroy removes them for good.

```bash
curl -X DELETE https://flaxcloud.com/v1/sandboxes/$SID -H "Authorization: Bearer $FLAX_API_KEY"
```

Idle sandboxes are reclaimed automatically (stopped or destroyed) - see
[Core concepts -> Lifecycle](./concepts.md#lifecycle).

## Troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| `402 memory_limit` | Requested memory is above your plan. Free is 1 GB, Pro is 2 GB, Builder is 4 GB, Team is 8 GB. | Choose a smaller memory size or upgrade. |
| `402 concurrency_limit` | You already have the plan's maximum live sandboxes. | Stop or destroy a sandbox, then retry. |
| Preview returns `502 preview_unreachable` | Nothing is listening on the port, or the server bound to `127.0.0.1`. | Start the server with `--bind 0.0.0.0` or equivalent. |
| Shareable preview returns `404` | The link was disabled, rotated, or the sandbox is not live. | Create a new link and keep the sandbox running. |
| CDP connection fails later | CDP URLs are short-lived. | Mint a new URL with `get_cdp_url()` / `getCdpUrl()` / `flax browser cdp-url`. |
| Files disappear after destroy | Destroy is permanent. | Use stop/resume or create a snapshot before destroying. |

## Next steps

- [Core concepts](./concepts.md) - how sandboxes, templates, and state work
- [Running commands](./commands.md) · [Files](./files.md) · [Previews](./previews.md)
- [Browser automation](./browser.md) · [Snapshots](./snapshots.md)
- [Plans & limits](./plans-and-limits.md) · [Troubleshooting](./troubleshooting.md) · [Security](./security.md)
- [Full API reference](./api.md)
