# Get started with the CLI

> Get openwaf-cloud, point it at the OpenWAF API, give it an API token safely and run your first read and your first change.

## Get the CLI

`openwaf-cloud` is a single binary. OpenWAF does not publish downloadable builds of it yet; if you want to use it, ask support@openwaf.dev. Everything it does is also available from the dashboard, the [API](https://developers.openwaf.dev/api/), the [SDKs](https://developers.openwaf.dev/sdk/) and the [MCP server](https://developers.openwaf.dev/mcp/).

Check that it runs:

```sh
openwaf-cloud ctl help
```

## Point it at the API

Set the API address once in your shell profile. The CLI adds the `/v1/…` paths itself, so give it the host only:

```sh
export OPENWAF_API_URL=https://dash.openwaf.dev
```

> **Caution**
>
> Always set `OPENWAF_API_URL` (or pass `--api https://dash.openwaf.dev`). Without it the CLI tries a local address and fails with `no se puede hablar con la API` ("cannot reach the API").


## Give it a token

Create an API token in the dashboard under **API tokens** with the role and scope you need: **Read only** is enough to look around, **Tech** to make changes. Tokens start with `owf_`.

The CLI never takes the token as an argument, so it does not end up in your shell history or the process list. Use one of:

**Token file**

Save the token in a file only you can read. The file may hold the bare token, or a single line `NAME_TOKEN=value`, so a `.env`-style file works too.

```sh
mkdir -p ~/.config/openwaf
read -rs TOKEN && printf '%s\n' "$TOKEN" > ~/.config/openwaf/token && unset TOKEN
chmod 600 ~/.config/openwaf/token
export OPENWAF_TOKEN_FILE=~/.config/openwaf/token
```

The CLI refuses a file that is not yours or that the group or others can read.
**Environment variable**

```sh
read -rs OPENWAF_TOKEN && export OPENWAF_TOKEN
```

Useful in CI, where the token comes from the pipeline's secret store.


Set only one of `OPENWAF_TOKEN` and `OPENWAF_TOKEN_FILE`; with both, the CLI stops.

## Choose the organisation

A token belongs to one organisation, and the CLI uses it by default. To be explicit, set `OPENWAF_ORG` (or `--org`) to the organisation's name or id:

```sh
export OPENWAF_ORG=acme
```

## First read

```sh
openwaf-cloud ctl zones list
openwaf-cloud ctl zones show example.com
openwaf-cloud ctl records list example.com
```

Zones are named by domain or id. Add `--json` to any read to get the API's answer as is.

## First change

Every change needs a reason. Try it as a simulation first:

```sh
openwaf-cloud ctl records add example.com type=TXT name=_cli-test content="hello" \
  --reason "Try the CLI" --dry-run
```

The CLI prints `Simulación sobre zona example.com: versión 7 → 8` ("simulation on zone … version 7 → 8") and the diff. Run it again without `--dry-run`: it simulates, shows the diff, asks `¿Aplicar? [s/N]` ("apply?") and applies when you answer `y`. Then undo it:

```sh
openwaf-cloud ctl records rm example.com _cli-test/TXT --reason "Remove the CLI test"
```

Next: [Changes: simulation and confirmation](https://developers.openwaf.dev/cli/changes/) and the [command reference](https://developers.openwaf.dev/cli/reference/zones/).
