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

# Spell tags

> Character-by-character pronunciation for emails, codes, acronyms, and serial numbers — including grouped spelling.

Wrapping text in `<spell>` tags causes each character to be read out
individually. Useful for email addresses, verification codes, acronyms, and
serial numbers.

```text theme={null}
"Contact us at <spell>hello@kugelaudio.com</spell>"
→  "Contact us at H, E, L, L · O · at · K, U, G, E · L, A, U, D · I, O dot C, O, M"
```

Each `·` above is a 500 ms pause: spelled content is automatically
[grouped](#grouping) so a listener can follow it.

<Note>
  Content inside `<spell>` automatically bypasses text normalization.
  `normalize: true` still normalizes the surrounding prose. Always set
  `language` so special characters (`@`, `.`, `-`, `_`) use the correct
  language-specific spoken words.
</Note>

## Character translations by language

| Character | English    | German      | French     | Spanish    |
| --------- | ---------- | ----------- | ---------- | ---------- |
| `@`       | at         | ät          | arobase    | arroba     |
| `.`       | dot        | Punkt       | point      | punto      |
| `-`       | dash       | Strich      | tiret      | guión      |
| `_`       | underscore | Unterstrich | underscore | guión bajo |

Letters are spelled with their phonetic names, digits with their spoken
names. Whitespace *inside* a spell block is read as the word "space" (or the
language's equivalent).

## Grouping

Spelled content is grouped automatically: a 500 ms pause every **four**
letters or digits, the way a human reads a code aloud.

```text theme={null}
"The VIN is <spell>1G1RC6E49BU123456</spell>"
→  "1, G, 1, R · C, 6, E, 4 · 9, B, U, 1 · 2, 3, 4, 5 · 6"
```

The counter restarts at every boundary — a space, a `.`, a `-`, or an `@` —
so each run of characters is grouped on its own. `@` additionally gets a
pause on both sides, keeping the two halves of an email address apart.

Multi-word content is grouped word by word, and the space between words is
still read as the word "space":

```text theme={null}
"The name is <spell>Anastasiia Masaltseva</spell>"
→  "A, N, A, S · T, A, S, I · I, A space M, A, S, A · L, T, S, E · V, A"
```

Override the group size with `group="N"`:

```text theme={null}
"Your code is <spell group="2">A4B9XZ</spell>"
→  "A, 4 · B, 9 · X, Z"
```

Use `group="0"` to switch grouping off and have the content read as one
unbroken run.

## Examples

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    # Email address
    audio = client.tts.generate(
        text="Email us at <spell>hello@kugelaudio.com</spell>",
        voice_id=1071,
        normalize=True,
        language="en",
    )

    # Verification code, grouped in pairs
    audio = client.tts.generate(
        text='Your code is <spell group="2">A4B9XZ</spell>',
        voice_id=1071,
        normalize=True,
        language="en",
    )

    # Acronym with context
    audio = client.tts.generate(
        text="We use <spell>TTS</spell>, text-to-speech, for audio output.",
        voice_id=1071,
        normalize=True,
        language="en",
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```typescript theme={null}
    // Email address
    const audio = await client.tts.generate({
      text: 'Email us at <spell>hello@kugelaudio.com</spell>',
      voiceId: 1071,
      normalize: true,
      language: 'en',
    });

    // Verification code, grouped in pairs
    const audio2 = await client.tts.generate({
      text: 'Your code is <spell group="2">A4B9XZ</spell>',
      voiceId: 1071,
      normalize: true,
      language: 'en',
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.kugelaudio.com/v1/tts/generate \
      -H "Authorization: Bearer $KUGELAUDIO_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "text": "Your code is <spell group=\"2\">A4B9XZ</spell>",
        "voice_id": 1071,
        "normalize": true,
        "language": "en"
      }' --output output.pcm
    ```
  </Tab>
</Tabs>

## Pitfalls

<Warning>
  Keep sentence-ending punctuation **outside** the tag.
  `<spell>D8239014.</spell>` reads the trailing period as the literal word
  "Dot" (or "Punkt" in German) and runs it into the next sentence. Write
  `<spell>D8239014</spell>.` instead.
</Warning>

* **No nesting.** A `<spell>` tag inside another spell block is read as
  literal characters.
* **No break tags inside spell blocks** — use [grouping](#grouping) for
  pacing instead.

## Spell tags in streaming

When streaming text token-by-token, spell tags that span multiple chunks are
handled automatically: the server buffers text until the closing `</spell>`
arrives before generating audio, and auto-closes incomplete tags if the
stream ends unexpectedly. See [Streaming overview](/streaming/overview).

## When spelling isn't enough

If a brand name or domain term is *pronounced* wrong (rather than needing to
be spelled out), use a [pronunciation dictionary](/prompting/pronunciation)
instead — it rewrites or IPA-annotates the word without changing your
request text.
