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

# The callva CLI

> Operate CallVA from a shell: one command per External API operation, JSON in and out, built for AI agents and scripts.

`callva` is a command-line client for the CallVA [External API](https://docs.callva.io/api-reference/introduction.md). Each command is one API operation, every answer is JSON on stdout, and errors are JSON on stderr with a stable exit code. It covers agents, speech-stack presets, agent tools, assets, calls, transcripts, recordings, call analytics, custom fields and field groups, webhook schedules, automations and their triggers, webhook logs, record actions, saved views, issues, knowledge, variables, settings, projects, phone numbers and telephony providers.

It is how an AI agent with a shell operates CallVA: the agent reads `callva help` once, then drives the platform with commands it can compose, retry and check by exit code. People use it the same way for scripts and one-off fixes.

> [card] CLI or MCP?
>
> Use the CLI where the agent has a shell and you can hand it an API key. Use [MCP](https://docs.callva.io/mcp.md) where the agent runs in a chat app and should connect through your own login, bound to one project.

> [card] [Source](https://github.com/ai-cluster-one/capabilities/tree/main/capabilities/callva)
>
> A single MIT-licensed script in the public `ai-cluster-one/capabilities` repository.

## Install

`callva` is one Python script that runs through [uv](https://docs.astral.sh/uv/). uv fetches Python 3.11 or newer and the script's dependencies on the first run, so uv is the only thing you install yourself.

**1. Install uv**

Skip this if `uv --version` already works.

```bash theme={null}
curl -LsSf https://astral.sh/uv/install.sh | sh
```

**2. Download the callva script**

Put it in a directory on your `PATH` and make it executable:

```bash theme={null}
mkdir -p ~/.local/bin
curl -fsSL -o ~/.local/bin/callva \
  https://raw.githubusercontent.com/ai-cluster-one/capabilities/main/capabilities/callva/bin/callva
chmod +x ~/.local/bin/callva
```

To pin a version, replace `main` in the URL with a commit hash from the repository.

**3. Check it runs**

```bash theme={null}
callva help
```

The first run takes a few seconds while uv installs the dependencies; later runs start at once. `callva help` prints the full command contract.

## Configure it

Run on its own, `callva` reads three environment variables and nothing else:

**CALLVA\_HEADLESS** `string` *required*

`read-only` serves every command that only reads. `read-write` also serves the commands that create, change, delete or run something. Start with `read-only` and switch when you mean to write.

**CALLVA\_API\_KEY** `string` *required*

A CallVA API key. Create one in the dashboard under **Settings > API Keys**; see [Authentication](https://docs.callva.io/authentication.md). The key's role decides what the CLI may do, whatever the mode.

**CALLVA\_API\_URL** `string` *required*

The API base, ending at `/api/v1`. The CLI appends `/external` itself. Set it to `https://api.callva.io/api/v1`: the script's built-in default points at a different host.

```bash theme={null}
export CALLVA_HEADLESS=read-only
export CALLVA_API_URL="https://api.callva.io/api/v1"
export CALLVA_API_KEY="<your API key>"

callva doctor
```

`doctor` makes one authenticated request and reports what the key sees:

```json theme={null}
{
  "ok": true,
  "connections": {
    "headless": {
      "base_url": "https://api.callva.io/api/v1",
      "key_env": "CALLVA_API_KEY",
      "ok": true,
      "projects_visible": 1,
      "sample_project": "[TEST] docs-4d48b3d0"
    }
  }
}
```

> [!WARNING]
>
> Never pass the key on the command line; the CLI has no flag for it on purpose. Keep it in the environment or in your secret manager, and use a project-scoped key for an agent that should reach one project only.

> [accordion] Project-scoped and organization-wide keys
>
> A **project-scoped** key works in its own project; you never name the project. Use it for agents.
>
> An **organization-wide** key reaches every project in the organization, so each project-level command names its project with `-f project_id=<id>` on lists, or a `project_id` key inside `--data` on writes. Creating, changing and deleting projects (`projects create|update|put|delete`) and adding phone numbers (`phone-numbers create`) need an organization-wide key.
>
> `callva doctor` and `callva projects list` take no project filter, so with an organization-wide key they fail with `PROJECT_REQUIRED`. Check such a key with a project-level read instead, for example `callva agents list -f project_id=<id>`.

> [accordion] What headless mode refuses
>
> In headless mode the CLI reads only its environment. It refuses `--connection`, `--key-env` and `--api-url`, and every flag that names a local file (`--data-file`, `--content-file`, `--prompt-file`, `--config-file`, `--inputs-file`, `--args-file`, `--file`, `--output`): pass content inline, and `recordings stream` writes audio to stdout. `settings reveal`, which prints a secret value, is refused in both modes.
>
> Headless mode also refuses to run (`headless_refused`) on a machine where the capabilities manager below has configured `callva`; use that setup there instead.

> [accordion] Using the capabilities manager instead
>
> `callva` is also published as a capability for the [`capabilities`](https://github.com/ai-cluster-one/capabilities) manager, which installs agent CLIs, keeps their credentials in a vault and lets one project hold several named connections (for example one per organization), each optionally read-only. If you already use it, install and enable it inside a project the manager has initialised (`capabilities init`), then add a connection; the API key travels on stdin, never on the command line:
>
> ```bash theme={null}
> capabilities install callva
> capabilities enable callva --project
> echo '{"secret_env": "<your API key>"}' | \
>   callva connection add callva-io --field api_url=https://api.callva.io/api/v1 --stdin --default
> callva doctor
> ```
>
> Select a connection per command with `--connection <id>`. `callva connections` shows where each value resolves from, with secrets masked. Without the manager, the environment variables above are all you need.

## How commands look

```text theme={null}
callva <resource> <action> [<id> ...] [--flag value ...] [-f key=value ...] [--full]
```

* **Filters** on lists and analytics are always `-f key=value`, repeatable: `calls list -f status=complete -f direction=outbound`.
* **Paging** on lists: `--per-page N --page N`.
* **Bodies** are JSON objects: `--data '{"...": ...}'`.
* **Lists are slimmed** to the fields an agent needs; add `--full` for the raw API response. `get` commands always return the full record.
* `callva routes` prints every command with its HTTP method and path, and whether it writes. It needs no key and no network.

## Common commands

The answers below come from a test project; ids are synthetic.

### List projects

```bash theme={null}
callva projects list
```

```json theme={null}
{
  "success": true,
  "message": "Projects retrieved successfully",
  "data": [
    {
      "id": "01a1c749-5525-731a-ab9f-61ffbf9e4ef2",
      "name": "[TEST] docs-4d48b3d0",
      "description": "Synthetic test data for a live check.",
      "is_active": true,
      "is_default": true
    }
  ],
  "pagination": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1, "from": 1, "to": 1 }
}
```

API: [List projects](https://docs.callva.io/api-reference/projects/list-projects.md).

### List calls

```bash theme={null}
callva calls list -f status=complete --per-page 5
```

```json theme={null}
{
  "success": true,
  "message": "Calls retrieved successfully",
  "data": [
    {
      "id": "01a1c74e-70be-73c8-a101-154da1c23b24",
      "name": "Test Caller",
      "phone": "+15555550100",
      "status": "complete",
      "direction": "outbound",
      "created_at": "2026-11-10T21:12:49.000000Z",
      "transcript": { "storage_type": "r2", "message_count": 2, "...": "..." },
      "appointment_confirmed": true
    },
    {
      "id": "01a1c74e-6512-7211-b944-187dcc2e84c5",
      "name": "Sam Sample",
      "phone": "+15555550101",
      "status": "complete",
      "direction": "outbound",
      "duration": 40,
      "cost": 0.15,
      "...": "..."
    }
  ],
  "pagination": { "current_page": 1, "last_page": 1, "per_page": 5, "total": 3, "from": 1, "to": 3 }
}
```

Every field of a call, built-in or custom, is a key on the record. API: [List calls](https://docs.callva.io/api-reference/calls/list-calls.md); see [Calls](https://docs.callva.io/guides/calls.md).

### Get a call

```bash theme={null}
callva calls get 01a1c74e-70be-73c8-a101-154da1c23b24
```

```json theme={null}
{
  "id": "01a1c74e-70be-73c8-a101-154da1c23b24",
  "tenant_id": "01a1c749-5387-7002-8154-5a7913629e6e",
  "project_id": "01a1c749-5525-731a-ab9f-61ffbf9e4ef2",
  "created_at": "2026-11-10T21:12:49.000000Z",
  "direction": "outbound",
  "name": "Test Caller",
  "phone": "+15555550100",
  "status": "scheduled",
  "transcript": {
    "storage_type": "r2",
    "key": "01a1c74e-70be-73c8-a101-154da1c23b24.json",
    "size_bytes": 570,
    "message_count": 2,
    "stored_at": "2026-11-10T21:12:55+00:00",
    "...": "..."
  }
}
```

API: [Get a call](https://docs.callva.io/api-reference/calls/get-a-call.md).

### Read a transcript

```bash theme={null}
callva transcripts get 01a1c74e-70be-73c8-a101-154da1c23b24
```

```json theme={null}
{
  "version": 1,
  "call_id": "01a1c74e-70be-73c8-a101-154da1c23b24",
  "tenant_id": "01a1c749-5387-7002-8154-5a7913629e6e",
  "project_id": "01a1c749-5525-731a-ab9f-61ffbf9e4ef2",
  "created_at": "2026-11-10T21:12:55+00:00",
  "messages": [
    { "role": "assistant", "content": "Hello, this is the clinic calling to confirm your appointment tomorrow at 10:00." },
    { "role": "user", "content": "Yes, I will be there." }
  ],
  "metadata": { "total_messages": 2 }
}
```

API: [Get a call's transcript](https://docs.callva.io/api-reference/transcripts/get-a-calls-transcript.md).

### Create a custom field

Writes need `CALLVA_HEADLESS=read-write` and a key whose role may create fields.

```bash theme={null}
CALLVA_HEADLESS=read-write callva fields create --data '{
  "entity_type": "call",
  "field_key": "appointment_confirmed",
  "field_label": "Appointment confirmed",
  "field_type": "boolean"
}'
```

```json theme={null}
{
  "extraction_enabled": false,
  "is_filterable": false,
  "is_sortable": false,
  "is_groupable": false,
  "is_visible": true,
  "entity_type": "call",
  "field_key": "appointment_confirmed",
  "field_label": "Appointment confirmed",
  "field_type": "boolean",
  "id": "01a1c74e-a56e-70f2-a98f-7b298f2a8105",
  "project_id": "01a1c749-5525-731a-ab9f-61ffbf9e4ef2",
  "tenant_id": "01a1c749-5387-7002-8154-5a7913629e6e",
  "updated_at": "2026-11-10T21:13:02.000000Z",
  "created_at": "2026-11-10T21:13:02.000000Z"
}
```

From then on the field is a key on every call: `callva calls update <call_id> --data '{"appointment_confirmed": true}'`. Before deleting a field, `callva fields impact <field_id>` counts the values it holds. API: [Create a custom field](https://docs.callva.io/api-reference/custom-fields/create-a-custom-field.md); see [Custom fields](https://docs.callva.io/guides/custom-fields.md).

### List webhook logs

```bash theme={null}
callva webhook-logs list --per-page 20
```

```json theme={null}
{
  "success": true,
  "message": "Webhook logs retrieved successfully",
  "data": [],
  "pagination": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 0, "from": null, "to": null }
}
```

`callva calls webhook-logs <call_id>` lists the logs of one call, and `callva webhook-logs filters` lists the values you can filter on. API: [List webhook logs](https://docs.callva.io/api-reference/webhook-logs/list-webhook-logs.md); see [Webhooks](https://docs.callva.io/guides/webhooks.md).

### Count calls by outcome

```bash theme={null}
callva stats aggregate --op count --group-by status
```

```json theme={null}
{
  "operation": "count",
  "field": null,
  "group_by": "status",
  "groups": [
    { "key": "complete", "value": 3 },
    { "key": "scheduled", "value": 1 },
    { "key": "null", "value": 1 }
  ]
}
```

`--op` is one of `count`, `sum`, `avg`, `min`, `max`; add `--field` for the others, `--interval day|week|month` for a time series, and `-f created_at_gte=<date>` to bound it. API: [Aggregate calls](https://docs.callva.io/api-reference/calls/aggregate-calls.md).

> [!WARNING]
>
> `callva call <destination> --agent-id <id>` places a real outbound call, and it is billed. Run it only when you mean to dial that number. See [Calls](https://docs.callva.io/guides/calls.md) for the request it sends.

## Errors and exit codes

An error is one JSON object on stderr:

```json theme={null}
{"error": {"code": "invalid_request", "message": "The entity type field is required.", "hint": "entity_type: The entity type field is required.", "status": 422}}
```

| Exit code | Meaning |
| - | - |
| `0` | Success; JSON on stdout. |
| `2` | Authentication: the key is missing or was refused (HTTP 401 or 403). |
| `3` | Not found (HTTP 404). |
| `4` | Policy refusal: a write in `read-only` mode, or a command headless mode does not serve. Change the mode only if the write is intended. |
| `5` | Server or network: timeout, connection error, 429 after retries, or 5xx. Safe to retry a read. |
| `6` | Input or validation: a malformed argument or a payload the API refused (HTTP 400 or 422). |

A write refused in read-only mode looks like this, with exit code `4`:

```json theme={null}
{"error": {"code": "read_only", "message": "'fields delete' writes, and CALLVA_HEADLESS is read-only", "hint": "Do not lift the gate yourself — ask the user; no flag or env value lifts it."}}
```

## Handing the CLI to an agent

Give the agent a shell with `callva` on its `PATH` and the three environment variables set, and tell it to start with `callva help`. The help text is written for agents: it states every command, its flags, what each one changes, and which commands write. Then:

* Give it a project-scoped key whose role holds only what the task needs, and `CALLVA_HEADLESS=read-only` unless it must write.
* Let it check its access with `callva doctor` before it starts.
* Let it branch on exit codes rather than parse messages.

> [card] [Connect over MCP](https://docs.callva.io/mcp.md)
>
> No shell? Connect a chat agent to one project through OAuth.

> [card] [API reference](https://docs.callva.io/api-reference/introduction.md)
>
> Every operation the CLI calls, with request and response schemas.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.