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

# Agents

> Create, configure, deploy, duplicate, transfer, and version voice agents.

An **agent** is the configuration that drives every ThunderPhone call —
the product tier, the voice, the languages, the system prompt, the
acknowledgement behavior, silence/voicemail handling, the attached
tools and knowledge, and whether the agent is reachable from the web
widget. Phone numbers assign an inbound and/or outbound agent; outbound
calls and mic sessions can target an agent directly.

Agents use a **draft / deploy** workflow: edits made via `PATCH`/`PUT`
are saved as a *draft* and do **not** affect production calls until you
`POST /deploy`. Test calls and mic sessions run against the draft (when
one exists) so you can try changes before shipping them.

## Endpoints

| Method          | Path                                         | Description                                       |
| --------------- | -------------------------------------------- | ------------------------------------------------- |
| `GET`           | `/v1/agents`                                 | List agents                                       |
| `POST`          | `/v1/agents`                                 | Create an agent                                   |
| `GET`           | `/v1/agents/{agent_id}`                      | Retrieve a single agent                           |
| `PUT` / `PATCH` | `/v1/agents/{agent_id}`                      | Save changes to the agent's **draft**             |
| `POST`          | `/v1/agents/{agent_id}/deploy`               | Promote the draft to the deployed config          |
| `POST`          | `/v1/agents/{agent_id}/discard-draft`        | Throw away all pending draft changes              |
| `DELETE`        | `/v1/agents/{agent_id}`                      | Delete an agent                                   |
| `POST`          | `/v1/agents/{agent_id}/duplicate`            | Duplicate an agent                                |
| `POST`          | `/v1/agents/{agent_id}/transfer`             | Copy or move an agent to another org              |
| `GET`           | `/v1/agents/{agent_id}/versions`             | List deployed configuration revisions             |
| `POST`          | `/v1/agents/prompt-language-check`           | Detect the language of a prompt                   |
| `POST`          | `/v1/agents/translate-prompt`                | Translate a prompt into another locale            |
| `POST`          | `/v1/agents/generate-acknowledgement-prompt` | Auto-generate a Storm-mode acknowledgement prompt |

Related agent-scoped surfaces documented on their own pages:
[test scenarios & suites](/api-reference/test-scenarios),
[split testing (A/B variants)](/api-reference/split-testing).

## Agent object

```json theme={null}
{
  "id": 12,
  "name": "Customer Support Agent",
  "prompt": "You are a helpful support agent for Acme Ops…",
  "voice": "john",
  "primary_language": "en",
  "additional_languages": [],
  "product": "spark",
  "thinking_level": "base",
  "background_track": "NONE",
  "acknowledgement_prompt_mode": "auto",
  "acknowledgement_prompt": "",
  "acknowledgement_feedback_mode": "acknowledgement",
  "inbound_speak_order": "agent_first",
  "outbound_speak_order": "caller_first",
  "voicemail_action": "prompt",
  "voicemail_message": "",
  "silence_interval_seconds": 15,
  "silence_max_checkins": 3,
  "silence_checkins_enabled": true,
  "connect_tone_enabled": false,
  "audio_context_mode": "full",
  "watchdog_enabled": false,
  "integrations": [],
  "knowledge_bases": [],
  "knowledge_documents": [],
  "mcp_servers": [],
  "widget_enabled": true,
  "split_testing_enabled": false,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z",
  "draft_prompt": null,
  "draft_voice": null,
  "draft_updated_at": null,
  "has_draft": false
}
```

### Deployed fields

| Field                           | Type            | Description                                                                                                           |
| ------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------- |
| `id`                            | integer         | Server-assigned agent id                                                                                              |
| `name`                          | string          | Human-readable name. 1–255 chars                                                                                      |
| `prompt`                        | string          | The system prompt that governs agent behavior                                                                         |
| `voice`                         | string          | Voice name from [`GET /v1/voices`](#voices) — e.g. `john`, `megan`                                                    |
| `primary_language`              | string          | ISO 639 code, e.g. `en`, `es`. Default `en`. Drives the default TTS locale                                            |
| `additional_languages`          | array of string | Extra language codes the agent supports (`es` or BCP-47 `es-ES`)                                                      |
| `product`                       | string          | Product tier. One of: `spark`, `bolt`, `storm-base`, `storm-base-with-ack`, `storm-extra`, `storm-extra-with-ack`     |
| `thinking_level`                | string          | `base` or `extra`. Derived from `product` for Storm tiers                                                             |
| `background_track`              | string          | Ambient audio track name, or `"NONE"` for silence. **Never `null`** — a `null` write is coerced to `"NONE"`           |
| `acknowledgement_prompt_mode`   | string          | `auto` (we generate the ack prompt) or `manual` (you supply it)                                                       |
| `acknowledgement_prompt`        | string          | Used when `acknowledgement_prompt_mode="manual"`. Storm-tier only                                                     |
| `acknowledgement_feedback_mode` | string          | While a Storm agent thinks: `acknowledgement` (spoken filler) or `tick` (ticking sound)                               |
| `inbound_speak_order`           | string          | Who talks first on inbound calls. `agent_first` or `caller_first`                                                     |
| `outbound_speak_order`          | string          | Who talks first on outbound calls                                                                                     |
| `voicemail_action`              | string          | What to do when a voicemail system answers: `prompt` (let the agent decide), `hangup`, or `message` (leave a message) |
| `voicemail_message`             | string          | TTS template for `voicemail_action="message"`, max 2000 chars. Supports `{agent_name}` and `{org_name}` variables     |
| `silence_interval_seconds`      | integer         | Seconds between "are you still there?" check-ins. 5–120, default 15                                                   |
| `silence_max_checkins`          | integer         | Check-ins before the agent hangs up. 1–10, default 3                                                                  |
| `silence_checkins_enabled`      | boolean         | Whether the agent proactively checks in during caller silence. Default `true`                                         |
| `connect_tone_enabled`          | boolean         | Play a short connection tone before the agent begins. Default `false`                                                 |
| `audio_context_mode`            | string          | Storm audio context window: `full` or `reduced` (lower latency, less prior audio)                                     |
| `watchdog_enabled`              | boolean         | Enables live supervision of agent turns (Storm). Default `false`                                                      |
| `integrations`                  | array           | Linked [Integration](/api-reference/integrations) objects                                                             |
| `knowledge_bases`               | array           | Attached [knowledge bases](/api-reference/knowledge-bases) (full objects)                                             |
| `knowledge_documents`           | array           | Individually attached [knowledge documents](/api-reference/knowledge-bases#knowledge-document-object)                 |
| `mcp_servers`                   | array           | Attached [MCP servers](/api-reference/mcp-servers) (full objects)                                                     |
| `widget_enabled`                | boolean         | Whether the agent is reachable via the embeddable web widget                                                          |
| `split_testing_enabled`         | boolean         | Whether calls are split across [A/B variants](/api-reference/split-testing)                                           |
| `created_at`, `updated_at`      | timestamp       | ISO 8601 UTC                                                                                                          |

### Draft fields

Every configurable field above has a `draft_*` mirror in the response
(`draft_name`, `draft_prompt`, `draft_voice`, `draft_primary_language`,
`draft_additional_languages`, `draft_product`, `draft_background_track`,
`draft_thinking_level`, `draft_acknowledgement_prompt_mode`,
`draft_acknowledgement_prompt`, `draft_acknowledgement_feedback_mode`,
`draft_inbound_speak_order`, `draft_outbound_speak_order`,
`draft_voicemail_action`, `draft_voicemail_message`,
`draft_silence_interval_seconds`, `draft_silence_max_checkins`,
`draft_silence_checkins_enabled`, `draft_connect_tone_enabled`,
`draft_audio_context_mode`, `draft_watchdog_enabled`,
`draft_widget_enabled`, `draft_split_testing_enabled`), plus draft id
lists for attachments (`draft_integration_ids`,
`draft_knowledge_base_ids`, `draft_knowledge_document_ids`,
`draft_mcp_server_ids`) and two read-only markers:

| Field              | Type                  | Description                                                                                |
| ------------------ | --------------------- | ------------------------------------------------------------------------------------------ |
| `draft_<field>`    | same as field \| null | `null` = no pending change for that field; non-null = the value staged for the next deploy |
| `draft_updated_at` | timestamp \| null     | When the draft was last edited                                                             |
| `has_draft`        | boolean               | True when any draft field is set                                                           |

Production call paths (inbound, outbound, widget) always read the
deployed fields. Mic sessions and simulations read the draft with
fallback to the deployed value.

### Product tiers at a glance

| Product                | Optimized for                                                | Acknowledgement                        |
| ---------------------- | ------------------------------------------------------------ | -------------------------------------- |
| `spark`                | Cost — fast and efficient for simple tasks                   | —                                      |
| `bolt`                 | Speed — the lowest-latency tier, balanced for most use cases | —                                      |
| `storm-base`           | Intelligence — complex prompts and reasoning                 | —                                      |
| `storm-base-with-ack`  | Intelligence                                                 | Spoken filler (or tick) while thinking |
| `storm-extra`          | Deepest reasoning                                            | —                                      |
| `storm-extra-with-ack` | Deepest reasoning                                            | Spoken filler (or tick) while thinking |

***

## List agents

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.thunderphone.com/v1/agents \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  agents = requests.get(
      "https://api.thunderphone.com/v1/agents",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  ).json()
  ```

  ```javascript Node.js theme={null}
  const agents = await fetch("https://api.thunderphone.com/v1/agents", {
    headers: { Authorization: `Bearer ${process.env.THUNDERPHONE_API_KEY}` },
  }).then((r) => r.json());
  ```
</CodeGroup>

Returns an array of [Agent objects](#agent-object), sorted by `created_at` descending.

***

## Create an agent

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Customer Support Agent",
      "prompt": "You are a helpful support agent for Acme Ops…",
      "voice": "john",
      "product": "spark",
      "widget_enabled": true
    }'
  ```

  ```python Python theme={null}
  agent = requests.post(
      "https://api.thunderphone.com/v1/agents",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={
          "name": "Customer Support Agent",
          "prompt": "You are a helpful support agent for Acme Ops…",
          "voice": "john",
          "product": "spark",
          "widget_enabled": True,
      },
  ).json()
  ```
</CodeGroup>

| Field                           | Type            | Required | Description                                                                                                          |
| ------------------------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `name`                          | string          | yes      | 1–255 chars                                                                                                          |
| `prompt`                        | string          | yes      | System prompt                                                                                                        |
| `voice`                         | string          | yes      | Voice name from [`/v1/voices`](#voices) (e.g. `john`) — anything else is rejected with `"Unsupported voice option."` |
| `primary_language`              | string          | no       | Defaults to `en`                                                                                                     |
| `additional_languages`          | array of string | no       | ISO 639 (`es`) or BCP-47 (`es-ES`) codes                                                                             |
| `product`                       | string          | no       | Defaults to `spark`                                                                                                  |
| `thinking_level`                | string          | no       | Ignored for Storm tiers (derived from `product`)                                                                     |
| `background_track`              | string          | no       | Track name or `"NONE"`                                                                                               |
| `acknowledgement_prompt_mode`   | string          | no       | `auto` or `manual`. Only meaningful for Storm-with-ack products                                                      |
| `acknowledgement_prompt`        | string          | no       | Required if `acknowledgement_prompt_mode="manual"`                                                                   |
| `acknowledgement_feedback_mode` | string          | no       | `acknowledgement` (default) or `tick`                                                                                |
| `inbound_speak_order`           | string          | no       | Defaults to `agent_first`                                                                                            |
| `outbound_speak_order`          | string          | no       | Defaults to `caller_first`                                                                                           |
| `voicemail_action`              | string          | no       | `prompt` (default), `hangup`, or `message`                                                                           |
| `voicemail_message`             | string          | no       | ≤ 2000 chars                                                                                                         |
| `silence_interval_seconds`      | integer         | no       | 5–120, default 15                                                                                                    |
| `silence_max_checkins`          | integer         | no       | 1–10, default 3                                                                                                      |
| `silence_checkins_enabled`      | boolean         | no       | Default `true`                                                                                                       |
| `connect_tone_enabled`          | boolean         | no       | Default `false`                                                                                                      |
| `audio_context_mode`            | string          | no       | `full` (default) or `reduced`                                                                                        |
| `watchdog_enabled`              | boolean         | no       | Default `false`                                                                                                      |
| `widget_enabled`                | boolean         | no       | Defaults to `true`                                                                                                   |
| `split_testing_enabled`         | boolean         | no       | Default `false`                                                                                                      |
| `integration_ids`               | array of UUID   | no       | Link reusable [integrations](/api-reference/integrations) by id                                                      |
| `knowledge_base_ids`            | array of UUID   | no       | Attach [knowledge bases](/api-reference/knowledge-bases)                                                             |
| `knowledge_document_ids`        | array of UUID   | no       | Attach individual knowledge documents                                                                                |
| `mcp_server_ids`                | array of UUID   | no       | Attach [MCP servers](/api-reference/mcp-servers)                                                                     |

Returns `201 Created` with the new [Agent object](#agent-object). A
create deploys immediately (there is no draft yet) and records revision
1 in the [version history](#version-history).

<Note>
  `max_hold_seconds` (outbound hold timeout, default 900 s) and inline
  `tools` exist on the underlying model but are **not writable through
  this API** — tool configuration is managed via
  [Integrations](/api-reference/integrations),
  [App connections](/api-reference/provider-connections), and
  [MCP servers](/api-reference/mcp-servers).
</Note>

***

## Retrieve an agent

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.thunderphone.com/v1/agents/12 \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  agent = requests.get(
      f"https://api.thunderphone.com/v1/agents/{agent_id}",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  ).json()
  ```
</CodeGroup>

Returns `200 OK` with an [Agent object](#agent-object), or `404` if not found.

***

## Update an agent (writes the draft)

`PATCH` and `PUT` do **not** modify the deployed configuration.
Every field you send is staged into the corresponding `draft_*` column;
production calls keep using the deployed values until you
[deploy](#deploy-the-draft). Sending a value identical to the deployed
value *clears* that field's draft (so manually reverting an edit
removes the pending change).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "You are a refined support agent…"}'
  ```

  ```python Python theme={null}
  agent = requests.patch(
      f"https://api.thunderphone.com/v1/agents/{agent_id}",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"prompt": "You are a refined support agent…"},
  ).json()
  ```
</CodeGroup>

Accepts the same fields as [create](#create-an-agent), including the
`integration_ids` / `knowledge_base_ids` / `knowledge_document_ids` /
`mcp_server_ids` lists (staged as draft attachment lists). Returns
`200 OK` with the [Agent object](#agent-object) — inspect the
`draft_*` fields and `has_draft` to see what is pending.

### Optimistic concurrency

To safely make edits from a UI, include `if_updated_at` (or
`updated_at`) with the last `updated_at` you observed:

```json theme={null}
{
  "prompt": "Newer prompt",
  "if_updated_at": "2026-04-20T18:24:10.113Z"
}
```

If the server-side `updated_at` differs, the API returns `409 Conflict`
with `{"detail": "Agent was modified by another user. Please refresh and try again."}`
so you can refresh and retry.

***

## Deploy the draft

Promotes every pending `draft_*` value to the deployed configuration,
clears the draft, and records a new revision in the
[version history](#version-history).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/12/deploy \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  agent = requests.post(
      f"https://api.thunderphone.com/v1/agents/{agent_id}/deploy",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  ).json()
  ```
</CodeGroup>

Returns `200 OK` with the updated [Agent object](#agent-object)
(`has_draft` is now `false`). Deploying with no pending draft is a
no-op that still returns `200` with the current agent.

## Discard the draft

Clears every pending draft field, reverting the editor state to the
deployed configuration.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/12/discard-draft \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```
</CodeGroup>

Returns `200 OK` with the [Agent object](#agent-object).

***

## Delete an agent

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://api.thunderphone.com/v1/agents/12 \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  requests.delete(
      f"https://api.thunderphone.com/v1/agents/{agent_id}",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  )
  ```
</CodeGroup>

Returns `204 No Content`. Phone numbers that reference the deleted agent
have their inbound/outbound assignment cleared.

***

## Duplicate an agent

Creates a new agent in the same org with the same **deployed**
configuration: name (overridable), prompt, voice, languages, product,
thinking level, background track, acknowledgement settings,
speak orders, voicemail settings, silence settings, connect tone,
audio context mode, watchdog, widget flag, and the attached
integrations, knowledge bases/documents, and MCP servers. Pending
drafts and split-testing variants are **not** copied.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/12/duplicate \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "Customer Support Agent (clone)"}'
  ```

  ```python Python theme={null}
  clone = requests.post(
      f"https://api.thunderphone.com/v1/agents/{agent_id}/duplicate",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"name": "Customer Support Agent (clone)"},
  ).json()
  ```
</CodeGroup>

| Field  | Type   | Required | Description                            |
| ------ | ------ | -------- | -------------------------------------- |
| `name` | string | no       | Defaults to `"<original name> (Copy)"` |

Returns `201 Created` with the new [Agent object](#agent-object).

***

## Transfer an agent to another org

Copy or move an agent to a different organization you're also a member
of. For `mode="move"`, `admin+` role is required on **both** orgs.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/12/transfer \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "target_org_id": 77,
      "mode": "copy"
    }'
  ```

  ```python Python theme={null}
  result = requests.post(
      f"https://api.thunderphone.com/v1/agents/{agent_id}/transfer",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"target_org_id": 77, "mode": "copy"},
  ).json()
  ```
</CodeGroup>

| Field           | Type    | Required | Description                                                         |
| --------------- | ------- | -------- | ------------------------------------------------------------------- |
| `target_org_id` | integer | yes      | For `mode="move"` it must differ from the source org id             |
| `mode`          | string  | no       | `copy` (default — keep source intact) or `move` (re-home the agent) |
| `name`          | string  | no       | Override the new agent's name                                       |

Returns `201 Created` for `copy` / `200 OK` for `move`:

```json theme={null}
{
  "mode": "copy",
  "source_org_id": 42,
  "target_org_id": 77,
  "agent": { /* Agent object in the target org */ }
}
```

<Note>
  Org-scoped attachments (integrations, knowledge, MCP servers) cannot
  cross the org boundary — the transferred agent keeps only attachments
  that already belong to the target org, which in practice means it
  starts with empty attachment lists.
</Note>

***

## Version history

Deploys (and creates/duplicates/transfers) record an
`AgentConfigVersion` snapshot of the **deployed** configuration.
Draft autosaves are *not* versioned — the history reflects what
actually shipped to production.

<CodeGroup>
  ```bash cURL theme={null}
  curl 'https://api.thunderphone.com/v1/agents/12/versions?limit=20' \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  versions = requests.get(
      f"https://api.thunderphone.com/v1/agents/{agent_id}/versions",
      params={"limit": 20},
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  ).json()
  ```
</CodeGroup>

| Query param | Default | Description                                   |
| ----------- | ------- | --------------------------------------------- |
| `limit`     | 20      | Max results. Values outside 1–100 are clamped |

Response:

```json theme={null}
{
  "count": 3,
  "results": [
    {
      "id": 501,
      "revision": 3,
      "created_by_id": 7,
      "created_at": "2026-04-20T18:24:10.113Z",
      "snapshot": { /* Deployed agent config at this revision */ },
      "changed_fields": ["prompt", "voice"]
    }
  ]
}
```

| Field            | Type            | Description                                   |
| ---------------- | --------------- | --------------------------------------------- |
| `id`             | integer         | Version row id                                |
| `revision`       | integer         | 1-based, increments per deploy                |
| `created_by_id`  | integer \| null | User id that deployed the revision            |
| `snapshot`       | object          | Full deployed config at this revision         |
| `changed_fields` | array of string | Fields that differ from the previous revision |

***

## Prompt helpers

These three endpoints are convenience wrappers that call the same
underlying models we use in the dashboard. All three take and return
JSON; none change any persisted resource.

### Detect prompt language

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/prompt-language-check \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Hola, gracias por llamar..."}'
  ```
</CodeGroup>

```json Response theme={null}
{
  "detected_language_code": "es",
  "detected_language_name": "Spanish",
  "mismatch": true,
  "provider": "gemini"
}
```

### Translate prompt

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/translate-prompt \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "prompt": "Hola, gracias por llamar…",
      "target_locale": "en-US"
    }'
  ```
</CodeGroup>

```json Response theme={null}
{
  "translated_prompt": "Hello, thank you for calling…",
  "source_language_code": "es",
  "source_language_name": "Spanish",
  "provider": "gemini",
  "used_fallback": false
}
```

### Generate acknowledgement prompt

Produces a short "filler while thinking" phrase appropriate for
Storm-with-ack products.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/agents/generate-acknowledgement-prompt \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "prompt": "You are a friendly receptionist for a dental office.",
      "target_locale": "en-US"
    }'
  ```
</CodeGroup>

```json Response theme={null}
{
  "acknowledgement_prompt": "Sure, let me take a quick look…",
  "provider": "gemini",
  "used_fallback": false
}
```

***

## Voices

List the supported voices and languages — or browse the [voice gallery](/api-reference/voices) with playable samples:

```bash theme={null}
curl 'https://api.thunderphone.com/v1/voices?languages=en,es' \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```

```json Response theme={null}
{
  "voices": [
    {
      "name": "john",
      "display_name": "John",
      "gender": "male",
      "category": "multilingual",
      "accent": "american",
      "languages": ["en", "es", "fr", "…"],
      "sample_url": "https://…/john.mp3?v=3"
    }
  ],
  "languages": [ /* language catalog entries */ ]
}
```

| Query param | Description                                                                 |
| ----------- | --------------------------------------------------------------------------- |
| `languages` | Comma-separated codes — only voices supporting **all** of them are returned |
| `category`  | Filter by voice category                                                    |
| `gender`    | Filter by voice gender                                                      |

The `name` is what you set on an agent's `voice` field.

***

## Related

<CardGroup cols={2}>
  <Card title="Phone Numbers" icon="phone" href="/api-reference/phone-numbers">
    Assign agents to inbound/outbound directions on phone numbers.
  </Card>

  <Card title="Knowledge bases" icon="book" href="/api-reference/knowledge-bases">
    Ground the agent in your documents.
  </Card>

  <Card title="Split testing" icon="shuffle" href="/api-reference/split-testing">
    A/B test prompt and voice variants on live traffic.
  </Card>

  <Card title="Test scenarios" icon="flask" href="/api-reference/test-scenarios">
    Regression-test the agent before deploying.
  </Card>
</CardGroup>
