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

# Narration Voices

> Browse the narration voice roster and choose the speaker for a course before it launches

Every course is narrated by one persona from a fixed roster. You browse the roster with a
catalogue call, then bind a voice to a course before that course launches. If you set nothing,
the course uses the roster default.

## The narration roster

```bash theme={null}
curl "https://api.myustadia.com/api/v1/voices" \
  -H "Authorization: Bearer sk_test_..."
```

Returns all ten narration personas. Each entry carries:

| Field | Meaning |
| - | - |
| `id` | The identifier you pass when setting a voice. This is the only voice identifier the API accepts or returns. |
| `default` | Marks the persona a course resolves to when you set nothing. |
| `live` | Marks the five personas that are also selectable in live mode. The other five are narration-only. |
| `preview_urls` | Per-language dictionary of audition clips. |

<Note>
  `preview_urls` is keyed by language. A language with no recorded clip yet is `null` rather than a
  dead link, so check for `null` before rendering a player.
</Note>

The underlying text-to-speech vendor voice name is never exposed. Do not attempt to pass one:
only a roster `id` is accepted.

## Narration roster versus the live roster

There are two catalogues and they are not interchangeable.

| Catalogue | Route | Contents |
| - | - | - |
| Narration | `GET /api/v1/voices` | All ten personas, for course narration |
| Live | `GET /api/v1/voice/voices` | The five vetted personas selectable in live mode |

The live catalogue is filtered to entries flagged `live` in the narration roster. A persona that
is narration-only cannot be used for a live session, and requesting one there will not resolve.

## Reading a course's voice

```bash theme={null}
curl "https://api.myustadia.com/api/v1/courses/$COURSE_ID/voice" \
  -H "Authorization: Bearer sk_test_..."
```

Read-only and always available. There is no status restriction on the read, so you can call it at
any point in a course's life to see the resolved narration voice.

## Setting a course's voice

```bash theme={null}
curl -X PUT "https://api.myustadia.com/api/v1/courses/$COURSE_ID/voice" \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"voice": "VOICE_ID_FROM_CATALOGUE"}'
```

Pass `"voice": null` to clear a previously chosen voice and fall back to the roster default.

<Warning>
  **A voice can only be set while the course is `awaiting_brief`.** Any later attempt returns
  `409 course_not_awaiting_brief`.

  This is deliberate rather than incidental. Once generation starts, the pipeline is already reading
  the course's preferences, so accepting a voice change afterwards would report a change that the
  audio does not reflect. Set the voice before you launch.
</Warning>

## Setting the voice at creation

You can skip the extra round trip by passing `voice` on the create request:

```bash theme={null}
curl -X POST "https://api.myustadia.com/api/v1/presets/$PRESET_ID/courses" \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"title": "Q3 Onboarding", "voice": "marc"}'
```

* An unknown id returns `400 invalid_voice`.
* Omitting `voice` leaves the existing default resolution in place, which takes the preset, gender
  and language into account.

## Ordering it correctly

1. `GET /api/v1/voices` and let the user pick, or hard-code a roster `id`.
2. Create the course. It lands in `awaiting_brief`.
3. `PUT /api/v1/courses/{course_id}/voice`, or pass `voice` on the create call in step 2.
4. Launch. From this point the voice is fixed for the course.


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