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

# Configuration and troubleshooting

> Global flags, output formats and JMESPath queries, paging, exit codes, config keys, reading the docs and opening the console from the terminal, reporting a bug, telemetry, and fixes for common errors.

Flags, output formats and exit codes that apply to every command, plus settings and fixes. For errors, jump to [Troubleshooting](#troubleshooting).

## Global flags

These flags work on any command (`plivo <command> [flags]`), with the exceptions noted. `--map` and `--version` belong on the root command.

| Flag | Description |
| - | - |
| `-o, --output <format>` | output format: `table`, `json`, `jsonl`, `yaml` or `csv`. Defaults to `table` on a terminal and `json` when piped. See [Output formats](https://plivo.com/docs/cli/configure.md#output-formats). |
| `--query <expression>` | filter the JSON output with a [JMESPath](https://jmespath.org) expression, such as `--query 'data.objects[].number'`. Implies `-o json`. See [Pick fields with --query](https://plivo.com/docs/cli/configure.md#pick-fields-with-jmespath). |
| `-y, --yes` | confirm a gated action, such as sending a message, buying a number or deleting a resource. A missing confirmation exits `5`. Some billed operations, including `lookup`, are not gated. |
| `--dry-run` | preview requests or local changes. It needs no `--yes`. Some commands still make account reads; see [Safety](#safety). |
| `--profile <name>` | run under a named profile from `~/.plivo/config.toml` instead of the active one. |
| `--timeout <duration>` | request timeout, in seconds or as a duration such as `90s` or `2m` (default `30s`). A value of 0 or less is refused. On `ask` and `diagnose`, a `--timeout` you pass also ends an answer that stalls, with `UPSTREAM_TIMEOUT` and exit code `3`. |
| `--map` | print every command with its arguments and flags as JSON. Needs no login. |
| `--schema` | describe the command (arguments, flags and, where the CLI reads them, response fields) instead of running it. For the diagnose commands, `sip test`, `voice streams test` and `sip connect plan`, it describes the result they print with `-o json`. Needs no login. |
| `--show-secrets` | show auth tokens and passwords in API responses. Without it they read `[REDACTED]`. See [Secrets in output](https://plivo.com/docs/cli/configure.md#secrets-in-output). |
| `--log-level <level>` | `debug`, `info`, `warn`, `error`, or `none` (default `warn`). `debug` prints every HTTP request and response to stderr. |
| `-q, --quiet` | suppress non-data output. |
| `--no-color` | disable colored output. |
| `-h, --help` | help for any command. |
| `-v, --version` | print the CLI version. Root command only, not after a subcommand. |

`--explain` is not a global flag. It narrates in plain English what a command will do before running it, and exists only on `api`, `account applications create`, `auth whoami`, `voice calls make`, `messaging sms send`, `messaging whatsapp send`, `messaging mms send`, `numbers buy`, `numbers release` and `verify sessions create`. Every other command rejects it.

## Output and exit codes

Most commands return a success object or an error object. Streaming commands are the exception: `ask -o json` and `ask -o jsonl` both emit JSON Lines, while `diagnose -o json` emits one result and `diagnose -o jsonl` emits events. See [Get help](https://plivo.com/docs/cli/apis/help.md) and [Diagnose a call](https://plivo.com/docs/cli/voice-agent/diagnose-call.md).

### Output formats

| `-o` | What you get |
| - | - |
| `table` | A readable table with a curated set of fields. The default on a terminal. |
| `json` | The full JSON envelope described below. The default when output is piped. |
| `jsonl` | One JSON record per line: each object of a list, or the one result. |
| `yaml` | The whole JSON envelope as YAML. |
| `csv` | One row per record, with a header row. A cell a spreadsheet would run as a formula is prefixed with `'`; `+` phone numbers and negative numbers are kept as they are. |

### Pick fields with JMESPath

`--query` runs a [JMESPath](https://jmespath.org) expression (a query language for selecting fields in JSON) on the JSON envelope before it is printed, and implies `-o json`. It also works with `-o jsonl`, `-o yaml` and `-o csv`. On `plivo api`, `--query` keeps its own meaning: a URL parameter as `key=value`.

```bash theme={null}
plivo numbers list --query 'data.objects[].number'
plivo voice calls list --since 2026-10-01 --until 2026-10-07 --query 'data.objects[].{uuid: call_uuid, cause: hangup_cause_name}'
```

* The dates are examples: a call range must be within the last 90 days and no longer than 31 days.
* An invalid expression is refused with `BAD_FLAG` and exit code `1`, before any request. An expression whose result grows too large, or that runs too long, ends with an error.
* An expression that fails only on the result: after a send, buy, create or other write, the request has already gone through, so the CLI prints the unfiltered result with a warning on stderr and exits `0`. Don't run the command again. On a read, it exits `1` with `BAD_FLAG`.

### Lists and paging

Most paged lists take `--limit` (1 to 20, default 20) and `--offset` (0 or more); invalid values are refused before any request. `account usage` is an exception: its limit is 1 to 1000, defaults to 100, and it has no `--offset`. Live calls and multiparty participants have no paging flags. `--all` reads every page into one result, and `meta.next` is `null` once every page is read. It stops after 100 pages (2,000 rows at `--limit 20`) with a warning and sets `meta.truncated: true`. A rate-limited page is retried for up to 61 seconds; if it still fails, the rows read so far are printed with `meta.truncated: true` and the command exits `4`. `--all` can't be combined with `--offset`, and `numbers search` doesn't take it. A filter value a list doesn't accept, such as a mistyped `--status` or `--direction`, is refused with the allowed values instead of returning an empty list. Date filters are described on the [Voice](https://plivo.com/docs/cli/apis/voice.md#recordings), [Messaging](https://plivo.com/docs/cli/apis/messaging.md) and [Make and control calls](https://plivo.com/docs/cli/voice-agent/calls.md) pages.

### Success envelope

With `-o json`, API reads place the response under `data`, with secrets redacted. A typical list:

```json theme={null}
{ "data": { "api_id": "example-request-id", "meta": { "limit": 20, "offset": 0, "total_count": 0 }, "objects": [] } }
```

Single resources sit directly under `data`. Most lists use `data.objects`, but Verify sessions use `data.sessions`, masking sessions `data.response.objects`, live call IDs `data.calls`, and usage rows `data.usage`. An empty list is `[]`, not `null`. Action commands print a result too (hangups, transfers, play, speak and DTMF, stream and recording stops, conference and multiparty actions, number release and update, and application, endpoint and subaccount updates and deletes): the API's response, or the ID and what was done, such as `{ "data": { "call_uuid": "<call_uuid>", "hung_up": true } }`.

`--dry-run` prints its preview on stderr, not stdout. IDs in the URL are escaped as they are when sent, so a `#` or `?` in an ID can't cut the path short. Local and workflow commands (`streams test`, `streams simulate`, `streams forward`, `upgrade`, `config telemetry`) honor `-o json` too: one summary on stdout, progress on stderr.

### Secrets in output

Auth tokens and passwords read `[REDACTED]` in every output format and in `plivo api` output: a subaccount's `auth_token` and `new_auth_token`, and an endpoint's `password`. Keys and their order stay the same. `account subaccounts create` still shows the new token once. Add `--show-secrets` to see the values.

### Error envelope

Errors go to stderr as JSON and the process exits non-zero:

```json theme={null}
{ "error": { "code": "RESOURCE_NOT_FOUND", "message": "CDR for call uuid … not found",
             "hint": "List available resources with the matching `... list` command.",
             "status_code": 404, "request_id": "…", "retryable": false } }
```

* Switch on `code`, never on message text. The HTTP status decides the code. When the API rejected the request, `context.upstream` holds its own response as `{status, body}`.
* `retryable` says whether sending the same request again is safe. A network failure (`NETWORK_ERROR`: connection refused, DNS, connection cut) or timeout (`UPSTREAM_TIMEOUT`) exits `3`, and is `retryable: true` only on a read (`GET`). After a failed write the request may have gone through, so check before sending it again.
* The CLI doesn't follow redirects: a 3xx exits `3` and names where it pointed. A mistyped subcommand or a stray argument fails with `BAD_INPUT` and a suggestion, even with `--help`.

### Exit codes

| Exit | Meaning | Typical `code` values |
| - | - | - |
| `0` | success | None |
| `1` | bad input, or the API rejected the request | `USER_ERROR`, `BAD_INPUT`, `VALIDATION_ERROR`, `RESOURCE_NOT_FOUND`, `UPSTREAM_ERROR` |
| `2` | authentication; also a WebSocket endpoint that refused `streams test` with 401 or 403 | `AUTH_MISSING`, `AUTH_INVALID`, `AUTH_FORBIDDEN`, `AUTH_EXPIRED` |
| `3` | network failure, timeout or Plivo-side failure, or a redirect (3xx); also an AI analysis that failed, stopped early or ran past `--timeout`, an unreachable `sip test`, a `streams test` endpoint that closed early, and a `streams forward` tunnel that stopped | `NETWORK_ERROR`, `UPSTREAM_TIMEOUT`, `UPSTREAM_UNAVAILABLE`, `UPSTREAM_ERROR`, `INTERNAL_ERROR` |
| `4` | rate limited | `RATE_LIMITED` |
| `5` | refused for safety | `DESTRUCTIVE_REFUSED`: a spend or delete command without `--yes`, or a delete of something another object depends on without `--force` |
| `6` | this CLI version is too old for the API | `CLI_TOO_OLD`; run `plivo upgrade` |
| `130` | interrupted (Ctrl-C) | None |

### Safety

* `voice calls make`, `messaging * send`, `numbers buy`, `numbers release`, resource deletes and mutating `plivo api` calls require `--yes`, checked locally. `--yes` is not a universal billing or account-change gate: `lookup` is billed without it, and updates can change routing without it.
* `--dry-run` previews a change without applying it. Some previews still read account data: `voice streams readiness --dry-run` runs account checks but doesn't request the answer URL, and SIP delete previews read dependent resources.
* Local commands preview too: `auth use`, `auth remove`, `logout`, `config set`, `config telemetry`, `login`, `upgrade`, `voice streams test` and `docs --refresh` describe the action without changing local state. `ask -i` refuses `--dry-run`.
* SIP trunking deletes read everything that depends on the object first, and refuse to delete something in use unless you add `--force` to `--yes`. Preview such a delete with `--dry-run --force`. See [SIP trunking](https://plivo.com/docs/cli/apis/sip.md#safety-rules).

## Configuration keys

`plivo config <subcommand>` views and changes settings in `~/.plivo/config.toml`. Two commands changing the file at once don't lose a change: each waits up to 10 seconds for the other.

| Command or environment variable | What it does |
| - | - |
| `plivo config telemetry on\|off\|status` | Turn identity telemetry on or off, or show its state. See [Telemetry](https://plivo.com/docs/cli/configure.md#telemetry). |
| `plivo config get <key>` / `plivo config set <key> <value>` | Read or write one setting. Supported key: `telemetry`. |
| `PLIVO_CLI_TELEMETRY=0` | disable identity telemetry for this shell or CI job. Wins over the config file. |
| `PLIVO_FEEDBACK_PROMPT=0` | silence the post-command feedback prompt. |
| `PLIVO_FEEDBACK_TELEMETRY=0` | disable `plivo feedback` submission entirely. |
| `PLIVO_NO_UPDATE_CHECK=1` | silence the "newer version available" hint. |
| `PLIVO_API_URL=<url>` | send every API request to a server on this machine, to see exactly what the CLI sends, such as `PLIVO_API_URL=http://127.0.0.1:18555/v1/cli/api`. The host must be `localhost`, `127.0.0.0/8` or `::1`, over http or https, with no user, query or fragment. Anything else is refused. |

The feedback switches take `0`, `false`, `off` or `no`. The feedback prompt never shows when output is piped, or while telemetry or feedback sending is off.

## Read the docs from the terminal

`plivo docs` reads the Plivo documentation from the shell. It needs no login, so it works before you log in, in CI containers, and in coding agents. For an answer with sources, use [`plivo ask`](https://plivo.com/docs/cli/apis/help#ask-a-question).

| Command | What it does |
| - | - |
| `plivo docs search <keywords...>` | Search the full text of every page. A page matches only if it has **all** the keywords, ranked by how often they appear. Matching ignores case and finds parts of words, so API field names work too. `--limit` sets the number of results (default 10). |
| `plivo docs list` | List every page. |
| `plivo docs show <path-or-title>` | Print one page in full. Give a URL, part of a path such as `voice/api/call`, or a page title. The most specific match wins. |

```bash theme={null}
plivo docs search 10dlc brand registration -o json
plivo docs show "Account API"
```

Text is cached under `~/.plivo/cache` for a day. If the network is down, the CLI serves the old cache. `--refresh` skips the cache, on `plivo docs` and all three subcommands; if a refresh fails, the CLI names the error and the cache's age. Without the CLI, add `.md` to any docs URL for plain Markdown. Two index files, which `plivo docs` also reads, cover the whole site for LLMs and agents:

```bash theme={null}
curl -s https://www.plivo.com/docs/llms.txt               # every page, with a one-line summary
curl -s https://www.plivo.com/docs/llms-full.txt          # every page, in one file
curl -s https://www.plivo.com/docs/voice/quickstart/quickstart.md
```

## Open the console or docs

`plivo open` opens the matching console or docs page in your browser, and prints the URL first in case no browser opens. No login is needed: the browser's console session applies. `--dry-run` prints the URL and opens nothing; `-o json` returns `{url, opened}`.

| Command | Opens |
| - | - |
| `plivo open` or `plivo open console` | The console home |
| `plivo open calls` | The voice call logs |
| `plivo open call <call_uuid>` | One voice call, with its Call Insights |
| `plivo open sip-call <call_uuid>` | One SIP trunking call |
| `plivo open numbers` | Your phone numbers |
| `plivo open docs [path]` | The docs home, or one page, such as `plivo open docs voice/api/calls` |

## Feedback and bug reports

`plivo feedback` sends a 1 to 5 rating and an optional comment, interactively or with `--rating` and `--message`. Phone numbers, emails, card numbers, IP addresses, bearer tokens, and Indian PAN and Aadhaar numbers are removed from comments before sending. Don't type other personal data or secrets into a comment. `plivo feedback --bug` sends your comment plus the last failed command, kept in `~/.plivo/last-error.json`: its command path, exit code, error code, request ID, CLI version and OS, never its arguments or the error text. The report is printed exactly as it will be sent, and you confirm first. Without a terminal pass `--yes`, or `--dry-run` to only print it. If sending fails, the CLI prints a prefilled GitHub issue link.

```bash theme={null}
plivo feedback --bug --dry-run                       # see what would be sent
plivo feedback --bug --message "what I expected" --yes
```

## Telemetry

The CLI sends a little usage data with each request so Plivo can see which commands are used, what fails, and which versions are in use. It is **on by default**; you can turn the identity part off at any time.

**Sent on every request:**

* CLI version, operating system and architecture (for the upgrade hint and compatibility), plus `Client-Type: cli` and `Client-Version` headers. These are sent even with telemetry off; they name the client, not you.
* The command name (for example `voice calls list`), never its arguments or flag values.
* With identity telemetry on: the account's Auth ID, the logged-in user's email, the account region, and a user identifier, to see usage per person within an organization.
* `plivo feedback` also sends the rating and comment you type.

**Never sent:** your auth token, API keys or passwords; phone numbers, call or message UUIDs, message bodies, audio or recordings; URLs you pass to commands (answer, WebSocket, callback); flag values, file contents, or anything from your Plivo account data.

**Turn it off:**

```bash theme={null}
plivo config telemetry off        # persistent, stored in ~/.plivo/config.toml
plivo config telemetry status
PLIVO_CLI_TELEMETRY=0 plivo voice calls list   # one shell or CI job; wins over the config file
```

`PLIVO_FEEDBACK_TELEMETRY=0` also disables `plivo feedback` submission.

## Troubleshooting

### Login, requests and output

| You see | It means | Do this |
| - | - | - |
| `AUTH_MISSING`, `AUTH_INVALID` or `AUTH_EXPIRED` (exit 2) | No credentials found, or they are wrong or expired | Run `plivo login`. The CLI does not read credentials from the environment |
| `DESTRUCTIVE_REFUSED` (exit 5) | A spend or delete command ran without `--yes` | Add `--yes`, or use `--dry-run` alone to preview |
| `RATE_LIMITED` on `ask` / `diagnose` | Per-account limit on assistant requests | Wait for the interval in the message |
| `NETWORK_ERROR` or `UPSTREAM_TIMEOUT` (exit 3) | Could not reach Plivo, or no answer in time | Check connectivity or VPN; `--log-level debug` shows the request. Retry only when `retryable` is `true` (a read). After a write, check whether it went through before sending it again |
| A warning that `--query` failed, with exit 0 | The expression failed on the result of a write that already went through | Don't run the command again. Fix the expression and use it on a read, such as the matching `get` |
| `RATE_LIMITED` (exit 4) on a list with `--all`, or in a loop | Too many requests in a short time | Wait a few seconds and retry; narrow the list with `--since` and `--until` instead of reading every page |
| `BAD_INPUT` (exit 1) with a suggestion | A mistyped subcommand or a stray argument | Use the suggested command; `plivo <command> --help` lists the real ones |
| A value refused before any request (exit 1) | An empty or blank value for a required flag, or an ID that is empty, `.` or `..` | Pass the real value |
| A redirect error (exit 3) | The API answered with a 3xx, which the CLI doesn't follow. The error names where it pointed | Check the path. A missing trailing slash is the usual cause |
| `BAD_FLAG` (exit 1) on `--limit`, `--offset`, `--status` or `--direction` | The value is outside what the API accepts (`--limit` is 1 to 20) | Use one of the allowed values printed in the error |
| `BAD_FLAG` (exit 1) on `--from` or `--to` of `messaging sms list`, `mms list` or `whatsapp list` | The Message API can't filter by number, so every message would come back | Use the `--query` filter the error suggests, with `--all` to read every page |
| A date range refused before any request (exit 1) | The range is longer than 31 days (calls, recordings) or starts more than 90 days ago | Run the ranges, or use the start date, that the error suggests |
| `CLI_TOO_OLD` (exit 6) | This CLI version is too old for the API | Run `plivo upgrade` (or `brew upgrade plivo`) |
| `interactive mode (-i) can't be combined with -o json` | Input is piped, so JSON output was selected | Add `-o table` |
| Table output looks truncated | Tables show a curated subset of fields | Use `-o json` for the full API response |

### Numbers and SIP trunking

| You see | It means | Do this |
| - | - | - |
| A `sip` command refused before any request (exit 1) | The value breaks a Plivo rule: a credential username that isn't 5 to 20 letters and digits, a password that isn't 5 to 20 characters with one of `~!@#$%^&*()_+`, an IPv6 address, an address Plivo can never reach (private, loopback and similar), an ID that isn't a UUID (or a trunk ID that isn't digits), a user part or a password inside a URI, or no `--name` on `create` | Fix the value as the error says. Give a URI as `host`, `host:port`, or `host:port;transport=tcp` (or `tls`) |
| `numbers update` or `sip connect plan` refused on an India (+91) number | The number has no KYC (compliance application) attached, or its application isn't `accepted`, or couldn't be read | Follow the KYC steps in the hint: file KYC, or check the application with `plivo numbers compliance get <id>`, then link it and retry. See [Numbers](https://plivo.com/docs/cli/apis/numbers.md#compliance-when-you-buy-or-route-a-number) |
| `DESTRUCTIVE_REFUSED` (exit 5) on a `sip … delete` with `--yes` | Something depends on the object: a number routed to the trunk, or a trunk using the URI, credential or IP list | Move or delete the dependents first, or add `--force` if you mean to break them. See [SIP trunking](https://plivo.com/docs/cli/apis/sip.md#safety-rules) |
| `sip connect plan` refused for an Indian number on Vapi | Vapi doesn't support Indian numbers | Use LiveKit or ElevenLabs; see [Connect a SIP platform](https://plivo.com/docs/cli/voice-agent/connect-sip-platform.md#indian-numbers) |
| `sip test` exits 3 with `unknown` | A UDP host didn't answer the SIP OPTIONS request; hosted platforms often ignore SIP from addresses they don't know | Not proof that calls will fail. Test the TCP or TLS URI if the platform has one |
| `sip test` exits 3 with `unreachable` | DNS failed or the port is closed from your network | Check the host and port against the platform's guide, and your firewall |
| `sip test` warns about a SIP SRV record | The host has no port, and its DNS names another SIP target | Test that target with the `--uri` the warning gives |

### Calls and Audio Streaming

| You see | It means | Do this |
| - | - | - |
| `voice calls get` returns not found for a call in progress | The call record is written when the call ends | Add `--live` to read the call while it is in progress |
| `diagnose` or `ask` exits 3 | The analysis failed, escalated or stopped early, or ran past the `--timeout` you passed (`UPSTREAM_TIMEOUT`) | Retry once; otherwise read the raw record with `plivo voice calls get <uuid>` or open it with `plivo open call <uuid>` |
| `voice streams test --expect-audio` exits 1 | Your voice agent sent no `playAudio` back | The test sends a tone, not speech: test with an echo agent, or make your agent speak first |
| `voice streams simulate` or `readiness` fails a check (exit 1) | Your answer URL, its XML or its `<Stream>` isn't what Plivo needs | Read the failed check in the table, or `checks[]` with `-o json`. See [Test your voice agent](https://plivo.com/docs/cli/voice-agent/test-websocket.md) |
| `voice streams test` exits 3 with a close code | Your endpoint closed the stream before the `stop` frame | Read the close code and reason in the error, and check your voice agent's logs |
| `voice streams test` fails with `AUTH_FORBIDDEN` (exit 2) | Your endpoint refused the WebSocket upgrade with 401 or 403 | Log in so the test signs the upgrade, or use `--profile` for the account your voice agent checks |
| `voice streams forward` exits 3 | The tunnel stopped. The application's answer URL was restored | Run `forward` again; try `--tunnel ngrok` or `--tunnel localhost.run` |
| `ssh not found, needed for the localhost.run tunnel` on `streams forward` | The default tunnel shells out to `ssh`, which is missing | Install an ssh client, or use `--tunnel ngrok` |
| The tunnel never comes up on `streams forward` | localhost.run was unreachable or refused the connection | Retry, or use `--tunnel ngrok` (needs ngrok on `PATH`) |

### Still stuck

Ask with `plivo ask "<what you see>"`. To report a CLI bug, run `plivo feedback --bug`, which attaches the last failed command (never its arguments). Send other feedback with `plivo feedback`, or open an issue on the [issue tracker](https://github.com/plivo/plivo-cli/issues). The CLI is open source under the Apache-2.0 license: [github.com/plivo/plivo-cli](https://github.com/plivo/plivo-cli).
