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

# Custom voices and avatars

> Upload a reference voice or a face image once, then reuse it by ID with every key you create.

Upload a reference voice or a face image once, then pass its ID on each request instead of sending the audio or image again.

| Asset | Upload | Use the ID in |
| - | - | - |
| Voice | `POST /v1/audio/voices` returns a `voice_id` | `voice` in [`POST /v1/audio/speech`](https://docs.boson.ai/models/higgs-tts/voices#custom-voices), and in a Realtime [`session.update`](https://docs.boson.ai/models/higgs-realtime/guides/audio-and-voices) |
| Avatar | `POST /v1/avatars` returns an `avatar_id` | `avatar_id` in [`POST /v1/avatar/sessions`](https://docs.boson.ai/models/higgs-avatar/realtime-sessions) |

## Who can use them

Your voices and avatars belong to your Boson account, not to the key that uploaded them. Every key you create on the [API Keys](https://www.boson.ai/workspace/api-key) page can list, use and delete them, so deleting or rotating a key loses nothing. A Realtime client secret acts for the key that created it.

A key that Boson issued to you directly, rather than one you created on the API Keys page, keeps its own voices and avatars.

Other accounts cannot see or use your voices and avatars. Boson's preset voices and avatars are available to everyone and cannot be deleted.

## Limits

| | Voices | Avatars |
| - | - | - |
| Per account | 200 | 100 |
| File size | 10 MB | 10 MB |
| Formats | WAV, MP3, FLAC, OGG/Opus | PNG, JPEG, WebP |
| Other | At least 3 seconds of audio; `ref_text` is required | At least 256 px on each edge |

Presets and deleted assets do not count toward the per-account limit. Uploading a file you already have returns the existing asset and does not count again, so a setup script is safe to re-run. A new upload past the limit returns `403 quota_exceeded`.

## Voices

### Create a voice

Send the reference audio with a verbatim transcript in `ref_text`, and an optional `title`. `ref_audio` can be a URL, base64, a `data:` URI, or a file in a `multipart/form-data` request. We recommend 5 to 30 seconds of clean speech from one speaker. Longer audio is cut to 30 seconds when it is used, and its transcript is then ignored.

```bash cURL theme={null}
curl https://api.boson.ai/v1/audio/voices \
  -H "Authorization: Bearer $BOSON_API_KEY" \
  -F ref_audio=@my-voice.wav \
  -F ref_text="The exact words spoken in my-voice.wav." \
  -F title="My voice"
# => {"voice_id": "voice_ab12...", "title": "My voice", "created_at": "...", "ref_text": "..."}
```

```python Python theme={null}
import os
import requests

API = "https://api.boson.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['BOSON_API_KEY']}"}

with open("my-voice.wav", "rb") as audio:
    created = requests.post(
        f"{API}/audio/voices",
        headers=headers,
        files={"ref_audio": audio},
        data={"ref_text": "The exact words spoken in my-voice.wav.", "title": "My voice"},
    )
created.raise_for_status()
voice_id = created.json()["voice_id"]
```

Uploading the same audio again returns the voice you already have, with its original `title` and `ref_text`. Pass the `voice_id` to `voice` in `POST /v1/audio/speech`; [Voices](https://docs.boson.ai/models/higgs-tts/voices.md#custom-voices) has complete examples.

### List, get and delete voices

| Route | Returns |
| - | - |
| `GET /v1/audio/voices` | Your account's voices (presets are not listed). |
| `GET /v1/audio/voices/{voice_id}` | One voice. Presets can be read too. |
| `DELETE /v1/audio/voices/{voice_id}` | `{"voice_id": "...", "object": "voice", "deleted": true}`. The voice stops working everywhere. |

```bash theme={null}
curl https://api.boson.ai/v1/audio/voices \
  -H "Authorization: Bearer $BOSON_API_KEY"
# => {"object": "list", "data": [{"voice_id": "voice_ab12...", "title": "My voice", "created_at": "..."}]}
```

## Avatars

### Upload an avatar

Send the image inline, either as a file in a `multipart/form-data` request or as base64 or a `data:` URI in a JSON body, with an optional `name` (up to 256 characters). URLs are not accepted. Use a clear photo of one person facing the camera.

```bash cURL theme={null}
curl https://api.boson.ai/v1/avatars \
  -H "Authorization: Bearer $BOSON_API_KEY" \
  -F image=@face.jpg \
  -F name="Support agent"
```

```python Python theme={null}
import base64
import os
import requests

API = "https://api.boson.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['BOSON_API_KEY']}"}

with open("face.jpg", "rb") as f:
    image = base64.b64encode(f.read()).decode()
created = requests.post(
    f"{API}/avatars", headers=headers, json={"image": image, "name": "Support agent"}
)
created.raise_for_status()
avatar_id = created.json()["avatar_id"]
```

```json Response theme={null}
{
  "avatar_id": "avatar_9f3c...",
  "object": "avatar",
  "name": "Support agent",
  "width": 1024,
  "height": 1366,
  "is_public": false,
  "created_at": "2026-11-04T10:00:00+00:00"
}
```

The image is rotated upright by its EXIF orientation, converted to RGB (transparency is dropped), and scaled down if an edge is over 2048 px; `width` and `height` describe the stored image. Uploading the same image again returns the avatar you already have. An image refused by the content check returns `400 content_policy_violation`.

To start a session with the avatar, pass its `avatar_id` to `POST /v1/avatar/sessions`; see [Realtime sessions](https://docs.boson.ai/models/higgs-avatar/realtime-sessions.md). `POST /v1/videos` does not take an `avatar_id`: send the image itself as `ref_image`.

### List, get and delete avatars

| Route | Returns |
| - | - |
| `GET /v1/avatars` | Boson's presets (`is_public: true`) and your account's avatars. |
| `GET /v1/avatars/{avatar_id}` | One avatar. |
| `DELETE /v1/avatars/{avatar_id}` | `{"avatar_id": "...", "object": "avatar", "deleted": true}`. New sessions can no longer use it. |

## Deleting

Deleting cannot be undone. Deleting a preset returns `403` (`voice_not_deletable` or `avatar_not_deletable`). An ID that does not exist, belongs to another account, or was already deleted returns one `404` (`voice_not_found` or `avatar_not_found`); the three cases are not distinguished, so the routes cannot be used to discover other accounts' IDs.

Uploading a deleted file again creates the asset again. With the same key you get the same ID back; with another of your keys you get a new ID.

## Errors

Errors use the common [error body](https://docs.boson.ai/api-reference/errors.md).

| Status | `code` | Meaning |
| - | - | - |
| `400` | `missing_required_field`, `invalid_field_value` | A required field is missing (`ref_audio`, `ref_text`, `image`), a value has the wrong type, or an avatar image was sent as a URL. |
| `400` | `unsupported_audio_format`, `reference_audio_too_short` | The audio cannot be decoded, or is shorter than 3 seconds. |
| `400` | `invalid_image`, `invalid_image_format`, `image_too_small`, `image_too_large` | The image cannot be decoded, is not PNG, JPEG or WebP, has an edge under 256 px, or has more than 40 million pixels. |
| `400` | `content_policy_violation` | The image was refused by the content check. `message` says why. |
| `403` | `quota_exceeded` | The per-account limit is reached. Delete assets you no longer need. |
| `403` | `voice_not_deletable`, `avatar_not_deletable` | Presets cannot be deleted. |
| `404` | `voice_not_found`, `avatar_not_found` | No such asset in your account. |
| `413` | `payload_too_large` | The file is over 10 MB. |
| `503` | `service_unavailable` | A temporary problem on Boson's side. Retry shortly. |


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