> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.narilabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.narilabs.com/_mcp/server.

# Generate speech

`POST https://api.narilabs.com/v1/audio/speech` converts complete text into speech. Set `stream: true` for progressive audio delivery, or omit it to receive the complete response.

## Prepare your text

Use normal capitalization and punctuation. All-lowercase text or text without punctuation can severely degrade speech quality.

Capitalize sentence starts and proper nouns, and include commas and sentence-ending punctuation where appropriate. The server does not automatically restore capitalization or missing punctuation. This is a speech-quality guideline, not an additional input validation requirement.

| Recommended                                 | Avoid                                    |
| ------------------------------------------- | ---------------------------------------- |
| `Hello, how are you? I'm glad you're here.` | `hello how are you i'm glad you're here` |

## Make a request

With your [API key](/authentication) in `NARI_API_KEY`, run:

```bash
curl --fail --silent --show-error \
  https://api.narilabs.com/v1/audio/speech \
  -H "Authorization: Bearer $NARI_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "model": "qwen3-tts:free",
    "input": "Your order has shipped.",
    "voice": "english_female_professional",
    "language": "en",
    "response_format": "wav",
    "stream": false
  }' \
  --dump-header response-headers.txt \
  --output speech.wav
```

| Field             | How to use it                                                                                                            |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `model`           | Required. Select a [Standard or Fast model](/models-and-pricing#text-to-speech); append `:free` for Free access.         |
| `input`           | Required. Send all text to synthesize in this request, with [normal capitalization and punctuation](#prepare-your-text). |
| `voice`           | Select a [voice ID](/voices). Defaults to `english_female_professional`.                                                 |
| `language`        | Use `en`, or omit it to select the voice's language with `auto`.                                                         |
| `response_format` | `wav` (default) or raw `pcm`.                                                                                            |
| `stream`          | `false` (default) for a complete response; `true` for progressive delivery.                                              |

The [API reference](/api-reference/text-to-speech/speech/generate-speech) defines field types, validation, and all error responses.

## Read the response

A successful request returns **HTTP 200 with binary audio**, rather than JSON or an audio URL. The example saves it to `speech.wav`, ready to open in an audio player.

| Header                     | Meaning                                                      |
| -------------------------- | ------------------------------------------------------------ |
| `Content-Type`             | `audio/wav` for WAV, or `audio/pcm` for raw PCM.             |
| `x-usage-input-characters` | Input character count after trimming surrounding whitespace. |
| `x-request-id`             | Request identifier for tracing failures and support.         |

Both formats contain **24 kHz, signed PCM16 little-endian, mono** audio. WAV includes a container header; PCM requires you to configure the playback format. [Streaming audio](/streaming-audio) covers playback and progressive delivery.

Errors detected before response headers are sent return a non-2xx status with a JSON body. Check the status before treating the body as audio; [Errors and troubleshooting](/errors) explains error codes and how to inspect them with cURL.

## Input limits

| Limit              | Value                                                             |
| ------------------ | ----------------------------------------------------------------- |
| Text length        | 1–2,048 Unicode code points after trimming surrounding whitespace |
| Complete JSON body | 64 KiB (65,536 bytes), including keys, values, and escaping       |

Whitespace-only text is rejected. Body size is checked before trimming. Text validation failures return `400`; oversized bodies return `413`. Split longer text into separate requests at sentence boundaries.

## Usage and access

Both Free and Partner models measure TTS usage by input characters. `x-usage-input-characters` reports the count for this request; [Usage and billing](/usage-and-billing) defines how characters are counted. The [daily Free allowance](/rate-limits#free-endpoint-limits) is separate from this measurement.

Successful Partner requests debit credits. Failed and cancelled requests do not debit credits. Partner models require early access and available credits. [Usage and billing](/usage-and-billing) explains pricing and credit handling.

## Rate limits

Free speech endpoints have endpoint-specific concurrent session and daily request limits. [Free tier and rate limits](/rate-limits#free-endpoint-limits) lists the current limits, response headers, and retry behavior for each `429` error.