# CLI

> The ayinbox command line interface. Sign in once, then drive campaigns, contacts, mailboxes and the inbox from your terminal, from CI, or from an agent.

Source: https://docs.ayinbox.com/api/cli/

`ayinbox` is the command line interface to AY Inbox. It signs in as you, holds one credential per host, and speaks only the public REST API, so it works against the hosted service and against any self-hosted instance you can reach.

```bash
ayinbox auth login
ayinbox campaign list
ayinbox inbox list --unseen
ayinbox api "/campaigns?limit=10"
```

<Callout type="info" title="This is not ayinboxctl">
  There are two CLIs and they answer different questions. `ayinbox` is the one you install on your machine to use the product. [`ayinboxctl`](/development/ayinboxctl/) is the operator's tool: it talks to Postgres directly, runs inside the backend container, and exists for recovery, accounts, health and backups. If you are asking "what is wrong with this install", that is the one you want.
</Callout>

Install [#install]

Pick one. All of them produce the same single binary.

**macOS and Linux**

```bash
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh
```

Installs to `~/.local/bin`, so it needs no root and no toolchain. The script verifies what it downloaded against the published checksum and installs nothing if they disagree, writes shell completions, and tells you the one line to add to your profile if that directory is not already on your PATH.

**Windows**

```powershell
irm https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.ps1 | iex
```

Installs to `%LOCALAPPDATA%\AyInbox\bin` and adds it to your user PATH. No admin rights.

**Homebrew** (macOS and Linux)

```bash
brew install walidboulanouar/tap/ayinbox
```

**Scoop** (Windows)

```powershell
scoop bucket add ayinbox https://github.com/walidboulanouar/homebrew-tap
scoop install ayinbox
```

**Docker**, for CI or anywhere installing a binary is more trouble than pulling one:

```bash
docker run --rm -e AYINBOX_TOKEN ghcr.io/walidboulanouar/ayinbox/cli campaign list
```

A container has no browser, so sign in with `AYINBOX_TOKEN` rather than `auth login`.

**From source**, if you have Go:

```bash
go install github.com/walidboulanouar/ayinbox/cmd/cli@latest
mv "$(go env GOPATH)/bin/cli" "$(go env GOPATH)/bin/ayinbox"
```

The package directory is `cmd/cli`, so `go install` names the binary `cli`. Rename it, or use one of the channels above.

**Already have an AY Inbox instance?** The binary ships inside the backend image:

```bash
docker compose -p ayinbox exec backend ayinbox --help
```

Keeping it current [#keeping-it-current]

```bash
ayinbox version
ayinbox upgrade
```

`upgrade` replaces the binary in place, verifying the download against the release checksums first. When the CLI came from Homebrew or Scoop it says which command to run instead, rather than overwriting a file a package manager owns. The CLI also checks for a new release once a day and mentions it in one line; `AYINBOX_NO_UPDATE_CHECK=1` turns that off, and it never runs in CI or when output is piped.

Installer flags [#installer-flags]

The install script takes flags after `--`, and every one of them is also an environment variable, so the same install runs from Ansible, cloud-init or a Dockerfile:

```bash
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh -s -- --dir /usr/local/bin
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh -s -- --version v1.4.0
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh -s -- --no-modify-path --no-completions
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh -s -- --dry-run
curl -fsSL https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh | sh -s -- --uninstall
```

| Flag               | Variable                 | What it does                                           |
| ------------------ | ------------------------ | ------------------------------------------------------ |
| `--dir PATH`       | `AYINBOX_INSTALL_DIR`    | Where the binary goes. Default `~/.local/bin`          |
| `--version TAG`    | `AYINBOX_CLI_VERSION`    | Pin a release instead of taking the newest             |
| `--base-url URL`   | `AYINBOX_CLI_BASE_URL`   | Download from an internal mirror of the release assets |
| `--no-modify-path` | `AYINBOX_NO_MODIFY_PATH` | Never touch a shell profile                            |
| `--no-completions` | `AYINBOX_NO_COMPLETIONS` | Skip the completion files                              |
| `--dry-run`        |                          | Print what would happen, change nothing                |
| `--uninstall`      |                          | Remove the binary and completions, keep your sign-ins  |

`--help` lists them in the terminal. `sh -s -- --help` works through the pipe.

Reading it before you run it [#reading-it-before-you-run-it]

Piping a script into a shell is worth being careful about, which is why the checksum is published next to it:

```bash
curl -fsSLO https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh
curl -fsSLO https://github.com/walidboulanouar/ayinbox/releases/latest/download/cli.sh.sha256
sha256sum -c cli.sh.sha256
less cli.sh && sh cli.sh
```

Every release archive is covered by `checksums.txt` on the release, and the installer verifies the archive against it before unpacking. If the two disagree it installs nothing and says so.

Completions [#completions]

The installer writes them for your shell. To do it by hand:

```bash
ayinbox completion bash > /etc/bash_completion.d/ayinbox
ayinbox completion zsh  > "${fpath[1]}/_ayinbox"
ayinbox completion fish > ~/.config/fish/completions/ayinbox.fish
```

Signing in [#signing-in]

```bash
ayinbox auth login
```

It asks two questions: which instance (the hosted service, or a hostname of your own), and how (a browser approval, or pasting a key you already have).

The browser path shows an eight character code, opens `app.ayinbox.com/cli`, and waits. You approve there, choosing which workspace the CLI is signing in to. The client name and machine name on that screen are whatever the terminal reported, so check that the code matches the one your terminal printed. Because approving creates a lasting credential, the screen asks you to confirm it is you (password or second factor) if you have not done so in the last few minutes, the same as creating an API key. The approval creates **one API key named for your machine** (its hostname up to the first dot), which appears under Settings > API keys and is revocable there or with `ayinbox auth logout`. The terminal never handles your password, and the browser never handles the key.

```
  Your code: K4TM-9RQD
  Approve at: https://app.ayinbox.com/cli?code=K4TM-9RQD

… Waiting for approval (the code expires in 10 minutes)
✓ Signed in to ayinbox.com as jane@example.com
  Workspace Acme
```

Non-interactive forms, for a script or an agent:

```bash
ayinbox auth login --hostname ayinbox.acme.com --web
echo "$AYINBOX_KEY" | ayinbox auth login --with-token
ayinbox auth login --scopes read-only
```

Scopes [#scopes]

The CLI asks for full access by default. The key it gets never carries more than your role in the chosen workspace allows: the approval screen lists the scopes the key will actually have for that workspace, and anything the CLI asked for beyond your role is left out. If your role allows none of them, the approval is refused with `cli_auth_scopes_role`. Narrow the request with `--scopes`:

```bash
ayinbox auth login --scopes read-only
ayinbox auth login --scopes read_campaigns,read_contacts,send_campaigns
```

A key's scopes are fixed once created, so widening them means a new key. `ayinbox auth refresh --scopes full` runs the sign-in again and revokes the key it replaces, which is why refreshing does not leave a trail of keys behind.

Scope names are the ones in the [permissions reference](/api/permissions/), in either case, with `full` and `read-only` as shorthands.

Several instances [#several-instances]

The CLI holds one credential per host. The `*` in `auth status` is the one commands use.

```bash
ayinbox auth login --hostname ayinbox.acme.com
ayinbox auth status
ayinbox auth switch ayinbox.acme.com
ayinbox campaign list --host ayinbox.com   # one command, other host
```

`ayinbox auth status` also tells you where the token came from, which is the answer nine times out of ten when a command fails unexpectedly:

```
* ayinbox.com
    ✓ signed in as jane@example.com
    - workspace: Acme
    - scopes: all 24
    - api: https://api.ayinbox.com
    - token from: /home/jane/.config/ayinbox/hosts.yml
    - token: aybox_ab********wxyz
```

In CI [#in-ci]

Set `AYINBOX_TOKEN` and skip the login entirely. It overrides the file and is never written to it.

```yaml
env:
  AYINBOX_TOKEN: ${{ secrets.AYINBOX_TOKEN }}
  AYINBOX_HOST: ayinbox.com     # omit for the hosted service
run: ayinbox campaign list --json
```

`ayinbox auth token` prints the active token and nothing else, for handing to another tool.

Output [#output]

Commands print a table on a terminal and JSON everywhere else, so the same command is readable by a person and parseable by a pipe.

```bash
ayinbox campaign list                      # a table
ayinbox campaign list > campaigns.json     # JSON, no flag needed
ayinbox campaign list --json | jq '.data[].name'
ayinbox campaign list --fields name,status
ayinbox campaign list --template '{{range .data}}{{.name}}{{"\n"}}{{end}}'
```

`--all` walks the cursor on any list command and merges every page into one response.

Sending real mail [#sending-real-mail]

Anything that puts mail on the wire asks first, and refuses rather than sending when there is no terminal to ask on:

```
$ ayinbox campaign start 6f1c…
! `ayinbox campaign start` sends real mail. Continue? [y/N]
```

`--yes` is the only way past it, which makes it the flag to grep for in a script review. The commands that behave this way are `campaign start`, `campaign test`, `placement test`, `placement batch-start`, `mailbox send`, `inbox reply`, `inbox compose` and `inbox approve-draft`. A flagged agent draft answers `draft_flagged` to `inbox approve-draft` until you read its flags and pass `--acknowledge-flags`.

Commands [#commands]

Run `ayinbox <command> --help` for the flags, and `ayinbox <command> <subcommand> --help` for one command's arguments.

| Command                                    | What it covers                                                                                                                                                                                                                                                                                                                                                                                                   |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auth`                                     | login, logout, status, token, switch, refresh                                                                                                                                                                                                                                                                                                                                                                    |
| `status`                                   | one screen: mailboxes needing attention, what is sending, what is unread                                                                                                                                                                                                                                                                                                                                         |
| `browse`                                   | open the dashboard, or one record, in a browser                                                                                                                                                                                                                                                                                                                                                                  |
| `campaign`                                 | list, view, create, edit, steps, senders, segments, preflight, test, start, stop, logs, plan, pause-lead / resume-lead / lead-hold, lead-cc / set-lead-cc / lead-cc-suggestions                                                                                                                                                                                                                                  |
| `contact`                                  | list, view, create, edit, delete, lookup, timeline, notes, import, export, verify                                                                                                                                                                                                                                                                                                                                |
| `mailbox`                                  | list, view, edit, health checks, sync state, send-as addresses, sending behaviour, warmup, hold, send                                                                                                                                                                                                                                                                                                            |
| `inbox`                                    | list, view, threads, read, reply, compose, drafts, scheduled sends, snoozes                                                                                                                                                                                                                                                                                                                                      |
| `suppression`                              | the addresses and domains that get no campaign mail                                                                                                                                                                                                                                                                                                                                                              |
| `segment`                                  | live audiences and their conditions                                                                                                                                                                                                                                                                                                                                                                              |
| `template`                                 | reply templates                                                                                                                                                                                                                                                                                                                                                                                                  |
| `automation`                               | automations, their runs and test firing                                                                                                                                                                                                                                                                                                                                                                          |
| `form`                                     | lead capture forms, submissions and stats                                                                                                                                                                                                                                                                                                                                                                        |
| `brain`                                    | [campaign brains](/guides/campaign-brain/): list, view, internal, create, update, delete, default, material-add / material-view / material-update / material-refresh / material-rm, pages / page-view / page-create / page-update / page-rm / page-history / page-restore, organize, preview, sample-reply, use, for-campaign. A file upload and the Obsidian vault download are dashboard or direct API actions |
| `booking`                                  | [calendar booking](/guides/booking/): `settings`, `settings-set` (off or draft), `auto`, `summary`, booking types (`types`, `types-create`, `types-update`, `types-delete`, `event-types`), `availability`, offers (`offers`, `offer`, `offer-create`, `stop`, `resume`, `reject`) and `book`, which asks before the provider invites the contact                                                                |
| `auto-reply`                               | [auto-reply](/guides/auto-reply/): status, enable, pause, runs, run, cancel, and per campaign `campaign`, `campaign-set` (off or shadow) and `campaign-enable` (automatic, with its settings; needs `SEND_CAMPAIGNS`)                                                                                                                                                                                            |
| `deal`, `pipeline`, `task`                 | the CRM                                                                                                                                                                                                                                                                                                                                                                                                          |
| `analytics`                                | dashboard, deliverability, warmup, per-mailbox and per-campaign numbers                                                                                                                                                                                                                                                                                                                                          |
| `placement`                                | [inbox placement tests](/guides/placement-tests/): overview, test, list, view, cancel, seed inboxes, a campaign's scheduled test, [batches](/guides/placement-tests/#testing-a-fleet-with-batches) across many mailboxes (`batch-preview`, `batch-start`, `batches`, `batch`, `batch-senders`, `batch-cancel`) and fleet `coverage`                                                                              |
| `audit`                                    | the workspace's audit trail                                                                                                                                                                                                                                                                                                                                                                                      |
| `advisor`                                  | recommendations, and applying or dismissing them                                                                                                                                                                                                                                                                                                                                                                 |
| `webhook`                                  | endpoints, deliveries, redelivery, event types                                                                                                                                                                                                                                                                                                                                                                   |
| `key`                                      | API keys, their scopes and their usage                                                                                                                                                                                                                                                                                                                                                                           |
| `oauth-app`                                | OAuth applications you publish                                                                                                                                                                                                                                                                                                                                                                                   |
| `integration`                              | third-party connections                                                                                                                                                                                                                                                                                                                                                                                          |
| `org`                                      | which workspace this credential belongs to                                                                                                                                                                                                                                                                                                                                                                       |
| `team`                                     | named groups of members, for CRM ownership and routing                                                                                                                                                                                                                                                                                                                                                           |
| `settings`                                 | workspace-wide outreach and suppression settings                                                                                                                                                                                                                                                                                                                                                                 |
| `warmup-routing`                           | which mailboxes warm with which                                                                                                                                                                                                                                                                                                                                                                                  |
| `tool`                                     | the AI tool registry, listed and called                                                                                                                                                                                                                                                                                                                                                                          |
| `events`                                   | the live event stream                                                                                                                                                                                                                                                                                                                                                                                            |
| `api`                                      | any endpoint at all                                                                                                                                                                                                                                                                                                                                                                                              |
| `upgrade`                                  | replace this binary with the newest release                                                                                                                                                                                                                                                                                                                                                                      |
| `config`, `alias`, `completion`, `version` | the CLI itself                                                                                                                                                                                                                                                                                                                                                                                                   |

Examples [#examples]

```bash
# Create a campaign, add a step, check it, start it
ayinbox campaign create --name "Q3 outbound" --daily-limit 40
ayinbox campaign add-step CAMPAIGN_ID --subject "Quick question" --wait-after 0
ayinbox campaign preflight CAMPAIGN_ID
ayinbox campaign start CAMPAIGN_ID

# Mailbox health across the workspace
ayinbox mailbox list
ayinbox mailbox check MAILBOX_ID
ayinbox mailbox edit MAILBOX_ID --daily-limit 40

# Send as a verified Gmail alias, and take the signature from Gmail
ayinbox mailbox identity MAILBOX_ID
ayinbox mailbox refresh-identity MAILBOX_ID --signature
ayinbox mailbox edit MAILBOX_ID --send-as hello@acme.com

# One contact is away: hold their sequence without unsubscribing them
ayinbox campaign pause-lead CAMPAIGN_ID CONTACT_ID --until 2026-09-21T17:00:00Z --reason "On holiday"
ayinbox campaign resume-lead CAMPAIGN_ID CONTACT_ID

# Two people at one company: copy the second on the first lead's emails
ayinbox campaign lead-cc-suggestions CAMPAIGN_ID CONTACT_ID
ayinbox campaign set-lead-cc CAMPAIGN_ID CONTACT_ID --cc COLLEAGUE_ID

# The inbox
ayinbox inbox list --unseen --limit 20
ayinbox inbox thread --email-id EMAIL_ID

# Contacts in and out
ayinbox contact create --email jane@example.com --first-name Jane --company Acme
ayinbox contact list --all --json > contacts.json
```

What needs the dashboard [#what-needs-the-dashboard]

Three things the CLI deliberately does not do, because the API does not let a key do them:

* **Connecting a mailbox.** It needs OAuth consent or a credential form in a browser. `ayinbox browse mailboxes` opens the right page.
* **Workspace administration.** Members, roles, invitations, workspace exports and the danger zone are session-only on the API: they depend on a human-bound session and refuse an API key. `ayinbox browse members` and `ayinbox browse settings` open them.
* **Billing.** Plans, checkout and credits are session-only for the same reason. `ayinbox browse billing`.

`ayinbox org view` still shows which workspace you are in, and `ayinbox team`, `ayinbox settings` and `ayinbox audit` cover the workspace surface a key can reach.

Watching events [#watching-events]

`ayinbox events tail` streams the developer WebSocket into your terminal: the same events the dashboard runs on, printed as they happen. It is the fastest way to see whether an integration is receiving what you think it is, without standing up a public endpoint first.

```bash
ayinbox events tail
ayinbox events tail --intent EMAIL --intent CAMPAIGN
ayinbox events tail --json | jq 'select(.event_type == "EMAIL_REPLIED")'
```

It needs a key with `REALTIME_SUBSCRIBE`; `ayinbox auth refresh --scopes full` gets one. The stream, its intents and its event types are documented under [Realtime](/api/realtime/).

Calling the API directly [#calling-the-api-directly]

`ayinbox api` reaches every endpoint, including the ones with no command of their own. Paths are relative to `/v1`.

```bash
ayinbox api /me
ayinbox api "/campaigns?limit=10" --paginate
ayinbox api /contacts -f email=jane@example.com -f first_name=Jane
ayinbox api /campaigns/CAMPAIGN_ID -X PATCH -F daily_limit=40
ayinbox api /contacts/search -X POST --input filter.json
ayinbox api /webhooks/WEBHOOK_ID -X DELETE
```

`-f` keeps a value a string. `-F` guesses the type, so `true`, `false`, `null` and numbers arrive as themselves, `@file` reads a value from a file, `key[sub]=v` nests and repeated `key[]=v` builds an array. `--paginate` follows the cursor, `-i` includes the status and headers, `--idempotency-key` rides the [documented header](/api/authentication/).

Configuration [#configuration]

Two files under `~/.config/ayinbox` (or `XDG_CONFIG_HOME`, or `AYINBOX_CONFIG_DIR`):

* `hosts.yml`, one credential per host, written 0600
* `config.yml`, preferences and aliases

Signing in records the instance's own API and dashboard URLs alongside the credential, taken from what the instance reports, so `browse` and `events tail` work on a self-hosted layout without anyone configuring a second address.

```bash
ayinbox config list
ayinbox config set output json      # default to JSON even on a terminal
ayinbox config set confirm always   # confirm every write, not only sends
ayinbox config set browser firefox
```

Aliases [#aliases]

```bash
ayinbox alias set hot "campaign list --status active"
ayinbox hot --json
```

Anything you type after the alias is appended, so an alias is a starting point rather than a fixed command.

Environment [#environment]

| Variable                  | What it does                                                         |
| ------------------------- | -------------------------------------------------------------------- |
| `AYINBOX_TOKEN`           | The API key to use. Overrides `hosts.yml` and is never written to it |
| `AYINBOX_API_KEY`         | The same thing under the name `ayinboxctl` uses                      |
| `AYINBOX_HOST`            | Which signed-in host to use                                          |
| `AYINBOX_API_URL`         | The API base URL, when it is not derivable from the host             |
| `AYINBOX_CONFIG_DIR`      | Where the two files live                                             |
| `AYINBOX_NO_UPDATE_CHECK` | Never check for a newer release                                      |
| `NO_COLOR`                | Turns colour off, as everywhere else                                 |

Exit codes [#exit-codes]

| Code | Meaning                                                                        |
| ---- | ------------------------------------------------------------------------------ |
| `0`  | It worked                                                                      |
| `1`  | The command failed, or you declined a prompt                                   |
| `2`  | The command line was wrong, or an answer was needed with no terminal to ask on |
| `4`  | Not signed in, or the credential was rejected or lacks a scope                 |

Every API failure prints the response's machine-readable `code` and `request_id` to stderr, so a script can branch without reading prose.

See also [#see-also]

* [Authentication](/api/authentication/) for how the device flow mints a key
* [Permissions](/api/permissions/) for what each scope allows
* [Endpoint scope map](/api/endpoints/) for what `ayinbox api` can reach
* [Realtime](/api/realtime/) for the stream behind `ayinbox events tail`
* [ayinboxctl](/development/ayinboxctl/) for the operator's CLI
