> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reply.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Using the CLI from agents & scripts

> The reply CLI's machine contract — JSON output, exit codes, the two error shapes, retries, impersonation headers, and composition patterns.

The `reply` CLI is built to be driven by coding agents, shell scripts, and CI. It handles the parts
that are tedious to reimplement — browser login, token refresh, the team header, retries — and
exposes the whole [v3 API](/api-reference/introduction) through
[`reply api`](/cli/overview#raw-api-access). That command is the agent surface today; there are no
dedicated resource commands yet.

## The `--json` contract

Every command accepts `--json` (compact) and `--pretty` (indented). **Data goes to stdout, status
and errors go to stderr** — pipes stay clean:

```bash theme={null}
reply api /v3/sequences --json | jq '.data.items[].id'
reply auth whoami --json | jq -r '.username'
reply team list --json | jq -r '.teams[].team_id'
```

`reply api` always emits JSON, with or without a flag — `{"code": <http status>, "data": <body>}`.
`--pretty` only changes the indentation.

## Exit codes

| Code | Meaning                                                                            |
| ---- | ---------------------------------------------------------------------------------- |
| `0`  | Success                                                                            |
| `1`  | API failure (HTTP `>= 400`) or runtime failure (network, corrupt credential store) |
| `2`  | Usage error — unknown flag, missing argument, no credential to use                 |

## The two error shapes

**`reply api` never hides an HTTP response.** Any status, including `4xx` and `5xx`, is printed on
stdout as `{code, data}`, where `data` is the v3 `problem+json` body verbatim. The exit code is `1`
for `>= 400`. Branch on `.code`:

```bash theme={null}
out=$(reply api /v3/contacts/999) || true
echo "$out" | jq -e '.code == 404' >/dev/null && echo "not found"
```

**Every other command** reports failures as a single machine-readable line on **stderr** when
`--json` or `--pretty` is set:

```json theme={null}
{"error":{"status":404,"code":"contact.notFound","title":"Not Found","detail":"Contact with ID 999 not found","hint":"Resource not found."}}
```

Branch on `code`, surface `hint` to the user. Every field except `title` is optional.

## Retries and rate limits

Handled inside the CLI, on both paths:

* `429`, `500`, `502`, `503`, and `504` are retried up to 3 times.
* `Retry-After` is honored when present, capped at 30 seconds; otherwise the backoff is exponential
  from 500 ms.
* Network failures are retried on the same schedule, then surface as a runtime error (exit `1`).

Don't wrap your own retry loop around write calls — a retried `POST` can double-create. Verify with
a follow-up `GET` instead. [Rate limits](/api-reference/rate-limits) documents the API-side windows.

## Teams and impersonation

Requests carry the team header from `--team-id` → `REPLY_TEAM_ID` → the profile's pinned team. If a
call needs a team and the credential spans several, the API returns `TEAM_REQUIRED` and the CLI adds
a one-line fix-it hint on stderr. Pin one non-interactively:

```bash theme={null}
reply team use 1045                        # persists on the active profile
reply --team-id 1045 api /v3/sequences     # or scope a single call
```

With an [organization API key](/api-reference/authentication#special-api-keys), name the acting user
with `--user-id <id>` or `--user-email <email>` (which also needs a team id). Pass exactly one.
These are **flag-only** — never read from the environment, never written to disk — so an agent must
supply them per invocation:

```bash theme={null}
reply --api-key "$ORG_KEY" --user-id 12345 api /v3/whoami
reply --api-key "$ORG_KEY" --team-id 1045 --user-email rep@acme.com api /v3/sequences
```

Rejection codes for organization keys are listed under
[Rejection responses](/api-reference/authentication#rejection-responses).

## Safety is the caller's job

<Warning>
  The CLI has **no `--dry-run` and no confirmation gates**. `reply api` sends exactly the request you
  give it — a `DELETE` deletes, and a `POST /v3/sequences/{id}/start` begins real outreach. The only
  interactive prompt in the whole CLI is `reply profile delete`, which `-y` skips.
</Warning>

An agent driving `reply api` owns the guardrails the [platform safety rules](/agents/safety)
describe: confirm high-stakes actions with the user first, echo the exact request you're about to
send, and prefer a read-back over a retry. Two habits that help:

* Resolve ids with a `GET` before mutating; never invent numeric ids.
* Use `--verbose` while developing a call — it prints the full request and response to stderr with
  credentials redacted, leaving stdout pipeable.

## Non-interactive environments

CI and agent sandboxes have no browser, so `reply auth login` won't work. Supply a key instead:

```bash theme={null}
export REPLY_API_KEY="$REPLY_KEY"      # or pass --api-key per call
reply auth whoami --json               # verify before doing work
```

Add `-q/--quiet` to silence progress messages on stderr; warnings and errors are still printed.
`REPLY_CONFIG_DIR` relocates the credential store when the default home directory isn't writable.

## Composition patterns

```bash theme={null}
# every active sequence's id and name, as TSV
reply api '/v3/sequences?status=active' --json \
  | jq -r '.data.items[] | [.id, .name] | @tsv'

# pause every active sequence whose reply rate was under 1% last week
reply api /v3/sequences/stats --body '{"filters":{"dateRangePreset":"lastWeek"}}' --json \
  | jq -r '.data[] | select(.status == "active" and .emailOverview.repliedPercentage < 1) | .sequenceId' \
  | xargs -I{} reply api /v3/sequences/{}/pause --method POST

# fail a CI job when the credential no longer works
reply auth whoami --json >/dev/null || exit 1
```

The CLI composes with cron for scheduled jobs, `jq` for filtering, and the
[Reply Skills](/skills/overview) for procedure — the skill supplies the plan, the CLI executes it.
Install them with `reply skills install`.

## Drop-in prompt

A ready-to-paste system prompt encoding this contract lives at
[Drop-in system prompts → CLI variant](/agents/prompts#cli-variant).
