# Quickstart

Create a sandbox, run a command, expose a port, and pause it. Takes about five minutes.

> **Private beta.** You need a beta account. [Join the waitlist](https://task.cloud/#waitlist). The Free plan includes 20 one-time hours of the `default` size, no card required.

## 1. Get an API key

Create a key in the dashboard (**Settings → API keys**) or with the CLI after `taskcloud login`:

```bash
taskcloud key create --name quickstart --preset full-sandbox
```

Keys look like `taskcloud_sk_...` and are shown once. Export it:

```bash
export TASKCLOUD_API_KEY="taskcloud_sk_..."
```

The SDKs and the CLI read `TASKCLOUD_API_KEY` automatically.

## 2. Install

```bash
npm install @taskcloud/sdk        # TypeScript / JavaScript (Node.js 20+; PTY needs Node.js 22+ or the `ws` package)
pip install taskcloud             # Python 3.9+
```

The CLI is built from source during the beta (`go build` in `cli/`, Go 1.27.3+); see [CLI](cli.md). The install script (`curl -fsSL https://task.cloud/install.sh | sh`) and prebuilt binaries work once the first CLI release is tagged.

## 3. Create a sandbox and run a command

### TypeScript

```ts
import { Client } from "@taskcloud/sdk";

const client = new Client(); // reads TASKCLOUD_API_KEY

const sandbox = await client.sandboxes.create({
  template: "base",
  size: "default",
  name: "quickstart",
  auto_pause: { enabled: true, idle_timeout_seconds: 300 },
});
console.log(sandbox.id, sandbox.state); // sbx_... running

const result = await sandbox.exec({ command: "uname -a && python3 --version" });
console.log(result.exit_code, result.stdout);
```

### Python

```python
from taskcloud import Client

client = Client()  # reads TASKCLOUD_API_KEY

sandbox = client.sandboxes.create(
    template="base",
    size="default",
    name="quickstart",
    auto_pause={"enabled": True, "idle_timeout_seconds": 300},
)
print(sandbox.id, sandbox.state)

result = sandbox.exec(command="uname -a && python3 --version")
print(result.exit_code, result.stdout)
```

### CLI

```bash
id=$(taskcloud create --template base --size default --name quickstart --json | jq -r .id)
taskcloud exec "$id" -- uname -a
```

### curl

```bash
API=https://api.task.cloud/v1

id=$(curl -sS -X POST "$API/sandboxes" \
  -H "Authorization: Bearer $TASKCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template":"base","size":"default","name":"quickstart"}' | jq -r .id)

curl -sS -X POST "$API/sandboxes/$id/exec" \
  -H "Authorization: Bearer $TASKCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command":"uname -a && python3 --version"}'
# {"command_id":"cmd_...","exit_code":0,"stdout":"Linux ...","stderr":"","duration_ms":41}
```

`POST /sandboxes` waits until the sandbox is `running` (target p95 < 500 ms from a template) and returns `201`. Pass `"wait": false` to get `202` immediately.

## 4. Start a server and open it in the browser

```ts
await sandbox.files.write("/home/user/www/index.html", "<h1>Hello from TaskCloud</h1>");
await sandbox.exec({ command: "python3 -m http.server 8080", cwd: "/home/user/www", background: true });
const port = await sandbox.ports.expose({ port: 8080, visibility: "public" });
console.log(port.url); // https://<short_id>-8080.taskhost.cloud
```

```python
sandbox.files.write("/home/user/www/index.html", "<h1>Hello from TaskCloud</h1>")
sandbox.exec(command="python3 -m http.server 8080", cwd="/home/user/www", background=True)
port = sandbox.ports.expose(port=8080, visibility="public")
print(port.url)
```

```bash
taskcloud exec "$id" --background --cwd /home/user/www -- python3 -m http.server 8080
taskcloud port expose "$id" 8080 --public
```

## 5. Pause, then wake it with a request

```ts
await sandbox.pause();            // RAM + disk snapshot; compute billing stops
// ...later: any request wakes it. Opening port.url, an SSH login or an API call all work:
const again = await sandbox.exec({ command: "echo still here" }); // resumes transparently
```

```bash
curl -sS -X POST "$API/sandboxes/$id/pause" -H "Authorization: Bearer $TASKCLOUD_API_KEY"
short=${id#sbx_}                                # hostnames use the ID without sbx_
curl -sS "https://$short-8080.taskhost.cloud/"   # wakes the sandbox, then serves the page
```

You do not have to pause manually: with the default `auto_pause`, a sandbox with no activity for 5 minutes pauses itself. See [Lifecycle](concepts/lifecycle.md).

## 6. Clean up

```ts
await sandbox.delete();
```

```bash
taskcloud delete "$id" --yes
```

## Next steps

- [Exec and files](guides/exec-and-files.md): streaming, background jobs, PTY, uploads, file watching.
- [Snapshots and fork](concepts/snapshots-and-fork.md): clone a running VM with its memory.
- [Desktop and computer use](guides/desktop-and-computer-use.md): give an agent a screen.
- [Webhooks](guides/webhooks.md): get notified when sandboxes pause, resume or fail.
- [Billing](billing.md): what you pay for, per state.
