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

# Pronunciation dictionaries

> Alias and phoneme entries applied per TTS request; 1,000 entries per dictionary

A pronunciation dictionary maps written forms to how they should be spoken. Each entry carries either an **alias** (replacement text, expanded at the gateway) or a **phoneme** (passed through to the model) — exactly one per entry. Attach a dictionary to any TTS request with `pronunciation_dict_id`.

## Endpoints

| Endpoint                               | Body                         | Returns                                            |
| -------------------------------------- | ---------------------------- | -------------------------------------------------- |
| `GET /pronunciation-dicts`             | —                            | `{"dicts": [{id, name, entry_count, created_at}]}` |
| `POST /pronunciation-dicts`            | `{"name": "..."}` (required) | 201, the dict                                      |
| `GET /pronunciation-dicts/:id`         | —                            | The dict with `entries`                            |
| `PATCH /pronunciation-dicts/:id`       | `{"name": "..."}`            | The dict                                           |
| `DELETE /pronunciation-dicts/:id`      | —                            | `{"id": "...", "deleted": true}` (soft delete)     |
| `PUT /pronunciation-dicts/:id/entries` | `{"entries": [...]}`         | `{"dict_id": "...", "entries": [...]}`             |

Unknown ids return 404 `dict_not_found`. `PUT /entries` replaces the full entry list — send every entry each time, not a delta.

## Entries

A dictionary holds up to **1,000 entries**.

| Field            | Constraint                                                    |
| ---------------- | ------------------------------------------------------------- |
| `grapheme`       | Required, 1–256 characters — the written form to match        |
| `alias`          | ≤256 characters — replacement text, expanded before synthesis |
| `phoneme`        | ≤256 characters — phonetic spelling, passed to the model      |
| `case_sensitive` | boolean — match `grapheme` exactly by case                    |

Each entry carries exactly one of `alias` or `phoneme`.

Create a dictionary and set its entries:

<CodeGroup>
  ```python Python theme={null}
  import requests

  headers = {"Authorization": "Bearer sk_hopper_..."}
  base = "https://api.withhopper.com"

  dict_id = requests.post(f"{base}/pronunciation-dicts", headers=headers,
                          json={"name": "Support terms"}).json()["id"]

  requests.put(f"{base}/pronunciation-dicts/{dict_id}/entries", headers=headers, json={
      "entries": [
          {"grapheme": "API", "alias": "A P I"},
          {"grapheme": "SQL", "alias": "sequel"},
          {"grapheme": "nginx", "phoneme": "ˈɛndʒɪnˌɛks"},
      ]
  })
  ```

  ```typescript TypeScript theme={null}
  const base = "https://api.withhopper.com";
  const headers = {
    Authorization: "Bearer sk_hopper_...",
    "Content-Type": "application/json",
  };

  const dict = await (await fetch(`${base}/pronunciation-dicts`, {
    method: "POST", headers, body: JSON.stringify({ name: "Support terms" }),
  })).json();

  await fetch(`${base}/pronunciation-dicts/${dict.id}/entries`, {
    method: "PUT",
    headers,
    body: JSON.stringify({
      entries: [
        { grapheme: "API", alias: "A P I" },
        { grapheme: "SQL", alias: "sequel" },
        { grapheme: "nginx", phoneme: "ˈɛndʒɪnˌɛks" },
      ],
    }),
  });
  ```

  ```bash cURL theme={null}
  curl -X PUT "https://api.withhopper.com/pronunciation-dicts/$DICT_ID/entries" \
    -H "Authorization: Bearer sk_hopper_..." \
    -H "Content-Type: application/json" \
    -d '{
      "entries": [
        {"grapheme": "API", "alias": "A P I"},
        {"grapheme": "SQL", "alias": "sequel"},
        {"grapheme": "nginx", "phoneme": "ˈɛndʒɪnˌɛks"}
      ]
    }'
  ```
</CodeGroup>

## How entries are applied

Pass the id on any TTS request:

```json theme={null}
{
  "model_id": "omnivoice",
  "transcript": "Connect to the API over SQL.",
  "voice": {"mode": "id", "id": "sarah"},
  "output_format": {"container": "wav", "sample_rate": 24000},
  "pronunciation_dict_id": "<dict_id>"
}
```

* **Alias entries** are expanded at the gateway before the transcript reaches the model. Matching is whole-word and case-insensitive unless the entry sets `case_sensitive`.
* **Phoneme entries** are not expanded; the gateway forwards them to the model as `pronunciations: [{grapheme, phoneme, case_sensitive}]`.

Billing uses the submitted transcript, before alias expansion. Expansion itself is capped at **20,000 characters**, 4× the 5,000-character transcript limit; a request that expands past it returns 400 `transcript_too_long`.
