# API: Voice agents

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/voice/agents` | Voice agents: persona, voice, language, tools, KB sections, runtime | `settings:read` |
| POST | `/v1/voice/agents` | Create a voice agent (owner) | `settings:write` |
| DELETE | `/v1/voice/agents/:id` | Archive a voice agent (owner) | `settings:write` |
| GET | `/v1/voice/agents/:id` | One voice agent with its saved versions | `settings:read` |
| PATCH | `/v1/voice/agents/:id` | Change a voice agent (owner); send the version you edited. Each save is a new version | `settings:write` |
| POST | `/v1/voice/agents/:id/preview` | Hear the persona: sample text spoken with its voice (BYO TTS key, metered) or text only | `settings:write` |
| GET | `/v1/voice/catalog` | The stock voice catalog (carrier voices; ElevenLabs and Cartesia when the organization brought its key), tone presets, languages and whether cloning is on | `settings:read` |
| GET | `/v1/voice/clips` | The hold clip and your voicemail drop (owners: everyone's) | `calls:read` |
| POST | `/v1/voice/clips` | Save the hold clip (owners) or your own voicemail drop: your recording, ElevenLabs or Cartesia speech (a stock voice or your own clone), or the carrier's speech (web app only) | `calls:write` |
| DELETE | `/v1/voice/clips/:id` | Retire a clip (your own drop; owners: any) | `calls:write` |
| GET | `/v1/voice/clones` | Voice-clone consents (owners see all; others their own) and the statement you'd read | `settings:read` |
| POST | `/v1/voice/clones` | Record your own spoken consent to clone your voice (only your own voice; refused while cloning is off) (web app only) | `calls:write` |
| DELETE | `/v1/voice/clones/:id` | Withdraw consent: the clone is deleted at the provider (you, or an owner) | `calls:write` |
| POST | `/v1/voice/clones/:id/clone` | Create your voice clone at the provider from your consented recording (web app only) | `calls:write` |
| POST | `/v1/voice/preview` | Hear an unsaved persona (owner) | `settings:write` |
| GET | `/v1/voice/runtimes` | Voice runtimes: our own pipeline (on), Retell and Vapi (off until their key is set), with the languages each speaks and the speech vendors' keys | `settings:read` |
| GET | `/v1/voice/sessions` | Voice sessions (one per call a voice agent answered), newest first, with p50/p95 end-of-speech → first-audio latency | `calls:read` |
| POST | `/v1/voice/sessions` | Open a voice session for a call (owner; the call layer does this when a call is answered): the media stream URL with its short-lived token, and the Conversation Relay settings | `settings:write` |
| GET | `/v1/voice/sessions/:id` | One voice session with every turn: what the caller said, the reply, what they heard before a barge-in, tools, KB used and latency | `transcripts:read` |

## Examples

### GET /v1/voice/agents

Voice agents: persona, voice, language, tools, KB sections, runtime

```bash
curl -s "https://api.closefinch.com/v1/voice/agents" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/agents

Create a voice agent (owner)

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/agents" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### DELETE /v1/voice/agents/$ID

Archive a voice agent (owner)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/agents/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/agents/$ID

One voice agent with its saved versions

```bash
curl -s "https://api.closefinch.com/v1/voice/agents/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PATCH /v1/voice/agents/$ID

Change a voice agent (owner); send the version you edited. Each save is a new version

```bash
curl -s -X PATCH "https://api.closefinch.com/v1/voice/agents/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents/${id}`, {
  method: "PATCH",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/voice/agents/$ID/preview

Hear the persona: sample text spoken with its voice (BYO TTS key, metered) or text only

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/agents/$ID/preview" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/agents/${id}/preview`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/catalog

The stock voice catalog (carrier voices; ElevenLabs and Cartesia when the organization brought its key), tone presets, languages and whether cloning is on

```bash
curl -s "https://api.closefinch.com/v1/voice/catalog" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/catalog`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/clips

The hold clip and your voicemail drop (owners: everyone's)

```bash
curl -s "https://api.closefinch.com/v1/voice/clips" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/clips`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### DELETE /v1/voice/clips/$ID

Retire a clip (your own drop; owners: any)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/clips/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/clips/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/clones

Voice-clone consents (owners see all; others their own) and the statement you'd read

```bash
curl -s "https://api.closefinch.com/v1/voice/clones" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/clones`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### DELETE /v1/voice/clones/$ID

Withdraw consent: the clone is deleted at the provider (you, or an owner)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/clones/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/clones/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/preview

Hear an unsaved persona (owner)

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/preview" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/preview`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/runtimes

Voice runtimes: our own pipeline (on), Retell and Vapi (off until their key is set), with the languages each speaks and the speech vendors' keys

```bash
curl -s "https://api.closefinch.com/v1/voice/runtimes" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/runtimes`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/sessions

Voice sessions (one per call a voice agent answered), newest first, with p50/p95 end-of-speech → first-audio latency

```bash
curl -s "https://api.closefinch.com/v1/voice/sessions" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/sessions`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/sessions

Open a voice session for a call (owner; the call layer does this when a call is answered): the media stream URL with its short-lived token, and the Conversation Relay settings

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/sessions" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/sessions`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/sessions/$ID

One voice session with every turn: what the caller said, the reply, what they heard before a barge-in, tools, KB used and latency

```bash
curl -s "https://api.closefinch.com/v1/voice/sessions/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/sessions/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

Request and response schemas: [https://www.closefinch.com/openapi.json](https://www.closefinch.com/openapi.json). All resources: [API reference](https://www.closefinch.com/docs/api).
