# Getting Started


Install the CLI, log in once, and the first command works. There is no client
to write: the CLI is a single binary for macOS, Linux, and Windows, on amd64 and
arm64, and it needs no runtime.

## Install

{{< tabs >}}

  {{< tab name="Homebrew" >}}
  ```bash
  brew install intuizi/intuizi-cli/intuizi
  ```
  macOS and Linux. Shell completion for bash, zsh, and fish comes with it.
  {{< /tab >}}

  {{< tab name="npm" >}}
  ```bash
  npm install -g @intuizi/cli
  ```
  macOS, Linux, and Windows. It needs Node 18 or newer. The package is a small
  launcher that pulls in the binary for your platform as an optional
  dependency, so nothing beyond the packages themselves is downloaded at
  install time.
  {{< /tab >}}

  {{< tab name="Binary" >}}
  Download the archive for your platform from the
  [releases page](https://github.com/intuizi/intuizi-cli/releases) on GitHub.
  Archive names carry the version without a leading `v`, such as
  `intuizi_0.1.6_linux_amd64.tar.gz`.

  On macOS and Linux, unpack it and move the binary onto your `PATH`:
  ```bash
  tar xzf intuizi_<version>_darwin_arm64.tar.gz
  xattr -d com.apple.quarantine intuizi   # macOS, when downloaded in a browser
  sudo mv intuizi /usr/local/bin/
  ```
  On macOS the `xattr` line clears the quarantine flag a browser download
  carries. Homebrew and npm installs skip that step.

  On Windows the archive is a `.zip`, such as
  `intuizi_<version>_windows_amd64.zip`. Extract `intuizi.exe` and put it in a
  folder on your `PATH`.

  Each release ships a `checksums.txt` for verifying an archive before
  unpacking it.
  {{< /tab >}}

{{< /tabs >}}

The CLI's source code and releases are on
[GitHub](https://github.com/intuizi/intuizi-cli). Report a bug or ask for a
feature in its [issues](https://github.com/intuizi/intuizi-cli/issues), and
for anything about your account, contact Intuizi support.

Confirm it worked:

```bash
intuizi version
```

It prints the version, such as `v0.1.6`.

The examples in this section use bash or zsh syntax, and some pipe `--json`
output through `jq`, which is installed separately. On Windows, run them in
Git Bash, or in WSL with the Linux build installed inside WSL (Homebrew, npm,
or the linux archive).

## Log in

```bash
intuizi auth login
```

Prompts for the email and password of your Intuizi Console account, exchanges
them for an API token, and keeps it for subsequent commands. Confirm it
worked:

```bash
intuizi auth status
```

```
Base URL: https://console.intuizi.com
Token:    present (in the OS credential store)
Account:  you@example.com
Expires:  2027-09-26 (in 364 days)
```

The token goes to the OS credential store when there is one: the macOS
Keychain, Windows Credential Manager, or the Linux secret service. Containers,
CI runners, and SSH sessions usually have none, so there it goes to the config
file, written with owner-only permissions: `~/.config/intuizi/config.json`
(`$XDG_CONFIG_HOME/intuizi/config.json` when that is set, and
`%AppData%\intuizi\config.json` on Windows). `INTUIZI_NO_KEYRING=1`, set before
logging in, keeps it in the file. The file also records the console URL, the
account, and the expiry,
and `auth status` says where the token is held.

`auth login` mints the same kind of API token as the My Account > API Tokens
page: it is listed there, expires after one year by default, and counts toward
the 10 active API tokens an account can hold. The contract is on
[Create API Token](/api/v2/authentication#post-apiv2authapitoken). Logging in
again reuses a working token already stored for the same console and account
rather than minting another. Pass `--email` to log in as another account,
which mints a token for it and replaces the stored one.

A token is bound to the console it was minted for. To use a console other than
`https://console.intuizi.com`, pass `--base-url` to `auth login`. Later
commands use the stored URL.

`intuizi auth logout` forgets the local copy and does not revoke the token. It
stays valid until it expires, until it is revoked on the My Account > API
Tokens page, or until the account password changes, which revokes every API
token on the account.

### In CI

Where nobody is there to type a password, mint an API token on the My Account >
API Tokens page and pass it in the `INTUIZI_API_TOKEN` environment variable
instead of running `auth login`. It wins over any stored token. A password
change revokes it, so CI needs a new one after that.

```bash
INTUIZI_API_TOKEN=<token> intuizi audiences list
```

Running `auth login` on a runner that starts with no stored token mints
another year-long token on every run, and those fill the cap of 10. See
[Scripts and CI](/cli/reference/auth#scripts-and-ci).

## First commands

Reference reads are the safest place to start: they are plain GETs with no
side effects.

```bash
intuizi reference common dataset-types
intuizi reference poi brands --search coffee
```

Every catalog except `reference profile-attributes recency-limits` takes
`--search`, a case-insensitive contains match.
[Catalogs](/cli/reference/catalogs) says which field each catalog matches.
Then look at what already exists in your account:

```bash
intuizi audiences list
intuizi projects list
```

## Output

| Flag | Prints |
| --- | --- |
| none | a table |
| `--json` | the raw [response envelope](/concepts/envelope) |
| `--quiet` | ids alone, one per line |

Commentary always goes to stderr: status changes while a command waits, the
pagination footer, "no results". Only data reaches stdout, so a pipe never has
to filter noise out.

```bash
intuizi reference poi brands --search coffee --quiet
intuizi audiences show <id> --json | jq '.data[0].status'
```

`--json` and `--quiet` contradict each other and are rejected together.
Commands that return no ids, such as `usage`, reject `--quiet`, so use
`--json` there. `auth`, `version`, and `completion` print plain text and
ignore either flag given alone.

`--debug` prints every HTTP request and response on stderr, with credentials
redacted, and leaves stdout alone. `--json`, `--quiet`, and `--debug` are three
of the five [global flags](/cli/reference#global-flags) every command takes.
The other two are `--base-url` (above) and `--idempotency-key` (below).

## Waiting

`audiences create` and `activations create` return as soon as the build is
queued, so a new audience comes back with a results count of zero. That is
expected, not a failure. Add `--wait` to block until it reaches Completed
(`104`) or fails:

```bash
intuizi audiences create --file audience.json --wait --timeout 30m
```

Status changes print to stderr as they happen. The last record read prints
to stdout whether the build completed or failed, or the wait timed out or gave
up, so branch on the exit code rather than the output: `0` is Completed, and `1`
is a failed build, a failed delivery, or a wait that timed out or gave up.
With `--json` stdout is always the server's envelope, so read
`.data[0].status.id`: a failed build still prints a `"status": "success"`
envelope, because reading the record succeeded, and a wait that timed out or
gave up prints the envelope it last polled. See
[Conventions](/cli/reference#conventions). `--quiet` prints the id whatever
the outcome.

The wait times out after 60 minutes unless `--timeout` sets another bound, and
`--timeout` without `--wait` is rejected. It also gives up after three failed
reads in a row, for example during a short API outage. Neither stops the build
on the server, so pick it up again with `intuizi audiences show <id> --wait`
(or `activations show`) rather than creating it again. Both a timeout and a
give-up name that command on stderr.

The wait keeps going while the build is still moving, including while an
audience draws the data stream visualizations it opted into, which it reports
as `109` Visualizing data streams before `105` and `104`. A failed build is
final and is not worth resuming. That includes `107` Additional Info, which
means Intuizi stopped the build because it cannot be built as defined. The API
reports only `Additional Info`. The Audience Manager shows the reason, most
often a date range outside the data available for the dataset, so fix what it
names and create the audience again. An activation that stops on `107` is
final in the same way.

`audiences show <id> --wait` also follows a Lookalike Model while it trains.
`audiences estimate create` and `audiences estimate show` wait on a size
estimate the same way, and it ends at `completed`, `blocked`, or `failed` (see
[Estimate show](/cli/reference/audiences#estimate-show)). No other command
waits. See [The Async Model](/concepts/async-model).

## Shell completion

A Homebrew install includes the completion scripts for bash, zsh, and fish.
After a binary or npm install, load the script the CLI generates for your
shell:

```bash
# zsh: add to ~/.zshrc
autoload -U compinit && compinit
source <(intuizi completion zsh)

# bash, with the bash-completion package: add to ~/.bashrc
source <(intuizi completion bash)

# fish: run once
mkdir -p ~/.config/fish/completions
intuizi completion fish > ~/.config/fish/completions/intuizi.fish
```

Zsh loads no completion, the Homebrew one included, until its completion
system is switched on, which is what the `compinit` line does. For PowerShell,
and for installing a script file instead, see
`intuizi completion <shell> --help`.

Completion covers commands, flag names, and the values of `--type`,
`--signal`, `--file-format`, `--identifier-type`, `schedules create
--frequency`, and `--purpose`.

## Limits

Rate limits are the API's: 120 reads and 30 writes per minute per token. Some
commands make more than one call, and each counts: a brand or category name is
looked up in its catalog, `audiences create` and `audiences estimate create`
read the signal-provider catalog for their default, `--wait` reads the record
until the work finishes, and `uploads put` also sends the file to storage.
Audience, estimate, Lookalike Model, cohort, and activation creates also count
against a per-organization build budget, by default 60 an hour and 300 a day,
counted across the console, the API, and MCP. See [Limits & Quotas](/concepts/limits).

On a `429` the CLI waits the interval the response asks for and retries at
most twice, saying so on stderr each time
(`rate limited (429): retrying in 3s (retry 1 of 2)`). That rides out the
per-minute limits. A `429` that asks for more than 60 seconds, as a
build-budget `429` usually does, is not retried: the command exits `1` at
once, and the error ends with the wait the server asked for, such as
`(429, Retry-After: 1800s)`. Nothing was created, so run the command again
after that. A create that claims an upload reference is retried only after the
per-minute limiter's `429`. A build-budget refusal of
`cohorts create --upload-reference` has already used the reference, so it is
returned as it came, and the error says to upload the file again for a new
reference. Do that once the budget has room. See
[Uploads](/cli/reference/uploads).

`audiences create`, `audiences estimate create`,
`audiences lookalike create`, `activations create`, `cohorts create`,
`projects create`, `schedules create`, and
`poi submissions create --upload-reference` send an `Idempotency-Key`, and a
retry after a `429` reuses it. Each run sends a fresh key, so running a create
again can make a second resource. When a create gets no response at all, the
CLI prints the key it used on stderr: run the same command with
`--idempotency-key <key>` to retry it without risking a duplicate. Other
writes send no key. See [Idempotency](/concepts/idempotency).

Exit codes: `0` success. `1` a failure once the command line parsed: an API
error, a `--wait` that failed, timed out, or gave up, or a local failure such
as an unreadable `--file`, a missing token, or a declined confirmation. `2` a
usage error: an unknown command or flag, a bad value or id, missing or
conflicting flags, a delete without `--yes` where stdin is not a terminal, or a
name that matches no catalog entry or several. Nothing is created on a `2`,
though a name lookup or the `--provider` check may already have read a catalog.
`130` on Ctrl-C and `143` on SIGTERM. With the npm package, `intuizi` is a Node
launcher. A SIGTERM or SIGHUP sent to the launcher alone, as Docker, systemd,
or a CI runner sends one, is passed on to the binary, so the command stops and
exits `143` for a SIGTERM, as it would without the launcher.

{{< cards >}}
  {{< card link="/developers/cli/" title="CLI" subtitle="What the CLI is, and when to use it." >}}
  {{< card link="/developers/cli/quickstart/" title="Quickstart" subtitle="Look up ids, build an audience, deliver it." >}}
{{< /cards >}}
