# Use the CLI

The `exayard` command line tool calls the Exayard API. It works for people and for agents: every command takes
`--json` for output a program can read, and every command ends with a stable exit code.

This guide is for `@exayard/cli` 0.5.0. It goes to npm with the next release.

```bash
npm install -g @exayard/cli
```

It needs Node 20 or later.

## Sign in

Sign in in the browser:

```bash
exayard login
```

The CLI opens the sign-in page and prints its address too, in case no browser opens. Calls are then made as you, in
your companies. If you belong to one company, it is saved. If you belong to several, pass `--org <company id>` to
`login` or to each call.

Or save an API key made on the [Developer page](https://developers.exayard.com/apps-and-keys.md):

```bash
exayard login --api-key exa_live_...
```

A key set to work in **This company** acts in its own company, so no command needs `--org`.

Both are saved to `~/.exayard/config.json`, readable only by you. A saved sign-in renews itself. Run `exayard login`
again if it ends. `EXAYARD_API_KEY`, `EXAYARD_ORG_ID` and `EXAYARD_BASE_URL` always win over the file, and a key
always wins over a browser sign-in. To see who you are signed in as, run `exayard get-me`.

## Name a company

A command needs a company only when your sign-in or key does not imply one:

- A **This company** key: never.
- A key set to work in **Every company that installed it**: always.
- A browser sign-in: when you belong to more than one company and saved none at login.

When you do name one, `--org` wins, then `EXAYARD_ORG_ID`, then the company saved at login. The value is the company's
ID, not its name. `exayard get-me` lists your companies under `memberships[].orgId`.

## List projects

```bash
exayard projects list
exayard projects list --json | jq '.[].name'
```

## Run a takeoff

```bash
exayard projects create --name "Main St clinic"
exayard files upload plans.pdf --project <project_id>
exayard pages list <project_id>
exayard assessments propose <project_id> --prompt "measure walls and roof"
exayard assessments run <project_id> --pages <page_id_1,page_id_2> --elements '<json>'
exayard takeoff summary <project_id>
```

`assessments latest`, `assessments list` and `assessments get` read the results. See
[Run a takeoff](https://developers.exayard.com/guides/run-a-takeoff.md) for the whole flow.

## Every API operation

Every operation in the API is also a command, named after the operation: `list_vendor_quotes` is
`exayard list-vendor-quotes`.

```bash
exayard api                                    # every command, grouped
exayard list-vendor-quotes --help              # one command's fields
exayard list-vendor-quotes <project_id> --status received
exayard update-labor-rate <rate_id> --input '{"hourlyRate": 85}'
```

Positional arguments fill the path. Every other field is a flag (`--quoteNumber` or `--quote-number`). A command that
deletes, uses AI, sends or buys runs only with `--yes`, so an agent driving the CLI can't do it by accident.

## Webhooks

```bash
exayard webhooks list
exayard webhooks create --url https://example.com/hooks/exayard --events "project.created,bid.generated"
exayard webhooks delete <endpoint_id>
```

### Forward events to your computer

`exayard listen` forwards your company's webhook events to a local address, so you can build a webhook handler without
a public URL:

```bash
exayard listen --forward-to http://localhost:3000/webhooks --events "bid.won,project.created"
```

- It prints a signing secret (`whsec_...`) when it starts. Each event is sent with the same body and
  `Exayard-Signature` header a real delivery has, signed with that secret, so your verification code runs unchanged.
- Without `--forward-to` it prints each event instead.
- Without `--events` every event is forwarded. `--name` labels the session.
- Ctrl-C stops it.

It needs an admin of the company, or a **This company** key with `write:webhooks`. See
[Subscribe to webhooks](https://developers.exayard.com/guides/subscribe-to-webhooks.md#forward-events-to-your-laptop-exayard-listen).

### Verify a signature

```bash
exayard webhooks verify --signature "$EXAYARD_SIGNATURE" --secret whsec_... < body.json
```

It exits 1 when the signature fails and prints the reason to stderr: `invalid_signature`, `replay_window_exceeded` or
`malformed_header`.

## Search help

```bash
exayard help-search "how do I run a takeoff"
```

`exayard init` writes an `agents.md` file into the current folder for coding agents.

## Global flags

| Flag | What it does |
| --- | --- |
| `--json` | Prints output a program can read, and nothing else |
| `--api-key <key>` | Uses this key for this call |
| `--org <id>` | The company to act in. A This company key needs none. |
| `--yes` | Runs a command that deletes, uses AI, sends or buys |

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | Success |
| `1` | The API refused or the operation failed. The message says why. |
| `2` | Usage error, such as a missing flag |
| `3` | Network or unexpected error |

Agents should branch on the exit code and read the `--json` output.
