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

# TTS SDK reference

> Synthesize speech with the Rime SDK in Python, Node.js, Go, or Rust, from streamed or complete text. This reference covers both calls, models and audio formats, options by language, and errors.

| Call | Use it when |
| - | - |
| `stream` | Text arrives in parts, such as tokens from an LLM. Synthesis can start after the first complete sentence, before the rest of the text arrives. |
| `synthesize` | You already have the complete, nonblank text. |

Both calls return streaming audio. Install the SDK from the [SDK overview](/api-reference/sdk/overview#install). This page lists the methods, options, defaults, and errors. For walkthroughs and complete programs, see the [SDK guides and examples](#guides-and-examples).

## Stream incremental text

`stream` takes a source of text fragments, and it returns audio chunks while the service makes them. By default, the audio is raw PCM16, little-endian, mono, at 24 kHz. Pass each fragment when it arrives. The SDK asks the service to collect the fragments into complete sentences before synthesis, so you do not need to split the text yourself.

![Text flows from your application through the backend Rime SDK to Rime TTS. Streaming audio returns through the SDK to your player or transport.](https://mintcdn.com/rimelabs/F3UJBXiHU5OG3Y-O/images/sdk/tts-flow.svg?fit=max\&auto=format\&n=F3UJBXiHU5OG3Y-O\&q=85\&s=ccba0f3493707613e8c5933b8e9ce50c)

Each example below reads text from your source and passes every audio chunk to `send_audio`, which stands for your player or transport. `client` is an open client. [Options by language](#options-by-language) gives the source types.

```python Python theme={null}
async with client.tts.stream(text_chunks) as audio:
    async for chunk in audio:
        await send_audio(chunk)
```

```typescript Node.js / TypeScript theme={null}
for await (const chunk of client.tts.stream(textChunks)) {
  await sendAudio(chunk);
}
```

```go Go theme={null}
audio, err := client.TTS.Stream(ctx, source, rime.SynthesisOptions{})
if err != nil {
	return err
}
defer audio.Close()
for {
	chunk, err := audio.Recv()
	if err == io.EOF {
		break
	}
	if err != nil {
		return err
	}
	if err := sendAudio(ctx, chunk); err != nil {
		return err
	}
}
```

```rust Rust theme={null}
let mut audio = client
    .tts()
    .stream(text_chunks, SynthesisOptions::default())?;
while let Some(chunk) = audio.next().await {
    send_audio(chunk?).await?;
}
```

## Synthesize complete text

`synthesize` takes one complete, nonblank string. It returns the same kind of audio stream as `stream`, and it does not buffer the entire audio response. Read the audio stream the same way.

```python Python theme={null}
audio = client.tts.synthesize("Your appointment is confirmed for tomorrow.")
```

```typescript Node.js / TypeScript theme={null}
const audio = client.tts.synthesize("Your appointment is confirmed for tomorrow.");
```

```go Go theme={null}
audio, err := client.TTS.Synthesize(ctx, "Your appointment is confirmed for tomorrow.", rime.SynthesisOptions{})
```

```rust Rust theme={null}
let mut audio = client.tts().synthesize(
    "Your appointment is confirmed for tomorrow.",
    SynthesisOptions::default(),
)?;
```

## Guides and examples

The [Rime SDK repository](https://github.com/rimelabs/rime-sdk) keeps the TTS guide and runnable examples for each language next to the SDK source.

| Language | TTS guide | Example programs |
| - | - | - |
| Python | [`python/docs/tts.md`](https://github.com/rimelabs/rime-sdk/blob/main/python/docs/tts.md) | <ul><li>[`tts/stream.py`](https://github.com/rimelabs/rime-sdk/blob/main/python/examples/tts/stream.py) saves streamed text as raw PCM.</li><li>[`tts/save.py`](https://github.com/rimelabs/rime-sdk/blob/main/python/examples/tts/save.py) saves a WAV file.</li></ul> |
| Node.js / TypeScript | [`typescript/docs/tts.md`](https://github.com/rimelabs/rime-sdk/blob/main/typescript/docs/tts.md) | <ul><li>[`tts/stream.mjs`](https://github.com/rimelabs/rime-sdk/blob/main/typescript/examples/tts/stream.mjs) saves streamed text as raw PCM.</li><li>[`tts/save.ts`](https://github.com/rimelabs/rime-sdk/blob/main/typescript/examples/tts/save.ts) saves a WAV file.</li></ul> |
| Go | [Go README, TTS section](https://github.com/rimelabs/rime-sdk/blob/main/go/README.md#tts) | <ul><li>[`examples/save`](https://github.com/rimelabs/rime-sdk/blob/main/go/examples/save/main.go) saves a WAV or mu-law file from complete or streamed text.</li></ul> |
| Rust | [Rust README, TTS section](https://github.com/rimelabs/rime-sdk/blob/main/rust/README.md#tts) | <ul><li>[`examples/save.rs`](https://github.com/rimelabs/rime-sdk/blob/main/rust/examples/save.rs) saves raw PCM.</li></ul> |

## Models and audio

Coda is the default model. The SDK also supports Mist v3. Both models use the language `en`, unless you set a different language.

| Model | Standard endpoint | Default voice |
| - | - | - |
| `coda` | `coda.api.rime.ai:443` | `clementine` |
| `mistv3` | `mist.api.rime.ai:443` | `astra` |

The SDK sends your API key as a bearer token over TLS. Set `RIME_API_KEY`, or give an explicit API key. The SDK does not load `.env` files.

A custom endpoint takes a hostname and an optional port. Do not include a scheme or a path. The default port is `443`.

| Output | Encoding | Sample rate | Channels |
| - | - | - | - |
| PCM | Signed 16-bit little-endian PCM | 24 kHz | Mono |
| Mu-law | G.711 mu-law | 8 kHz | Mono |

PCM and mu-law chunks have no file header. Each chunk contains complete sample frames, but the chunk sizes vary. Send the chunks to your player, or add a header to save a WAV file.

The current releases also offer WAV and MP3 output. Those chunks are fragments of one file. For a complete WAV file, select WAV output and call the buffer helper:

| Language | Buffer helper |
| - | - |
| Python | `synthesize_to_buffer` |
| Node.js | `synthesizeToBuffer` |
| Go | `SynthesizeToBuffer` |
| Rust | `synthesize_to_buffer` |

## Completion and errors

A stream can return audio before it fails. Treat the output as complete only after the stream ends successfully. The SDK does not retry synthesis automatically.

Overall timeouts include pauses between reads. If you disable the overall timeout, the internal connection and progress limits stay active. Discovery allows at most 10 seconds, and if you supply a shorter deadline, the shorter deadline applies.

| Failure | Python / TypeScript class | Go sentinel | Rust `ErrorKind` |
| - | - | - | - |
| Missing or rejected credentials | `RimeAuthenticationError` | `rime.ErrAuthentication` | `Authentication` |
| Access denied | `RimePermissionError` | `rime.ErrPermission` | `Permission` |
| Invalid input or client use | `RimeInputError` | `rime.ErrInput` | `Input` |
| Resource limit reached | `RimeResourceLimitError` | `rime.ErrResourceLimit` | `ResourceLimit` |
| Service unavailable | `RimeUnavailableError` | `rime.ErrUnavailable` | `Unavailable` |
| Overall or internal deadline reached | `RimeTimeoutError` | `rime.ErrTimeout` | `Timeout` |
| Unsupported or unexpected audio format | `RimeAudioFormatError` | `rime.ErrAudioFormat` | `AudioFormat` |
| Operation cancelled | `RimeCancelledError` | `rime.ErrCancelled` | `Cancelled` |
| Other stream or transport failure | `RimeStreamError` | `rime.ErrStream` | `Stream` |

Python and TypeScript errors inherit from `RimeError`. In Go, use `errors.Is` for categories and `errors.As` for request details. In Rust, `error.kind()` gives the category. Keep the request ID when you report a failure.

## Options by language

**Python**

The [Python package](https://github.com/rimelabs/rime-sdk/tree/main/python) has installation steps and examples.

`stream` accepts an async iterable of strings. Do not await the method call. Work starts when you enter the async context of the stream or read the first chunk.

### Client options

Select Mist v3 with `Rime(model="mistv3")`.

| `Rime(...)` option | Default | Meaning |
| - | - | - |
| `api_key` | `RIME_API_KEY` | The API key. An explicit value overrides the environment. |
| `model` | `"coda"` | The model for speech and discovery |
| `endpoint` | Model's standard endpoint | A custom hostname and optional port for speech and discovery |
| `timeout` | `None` | The overall deadline, in positive seconds as an `int` or `float`, or a positive `datetime.timedelta`. `None` disables it. A `timedelta` needs 0.1.0a17 or later. |

For a custom deployment, set `endpoint="host:8443"`.

### Synthesis options

Use `stream(source, ...)` for an async iterable of strings. Use `synthesize(text, ...)` for a nonblank string. Both accept the same optional keyword arguments:

| Option | Default | Meaning |
| - | - | - |
| `voice` | Model's default voice | A voice name from `client.voices.list()` |
| `language` | `"en"` | The language code |
| `audio_format` | `AudioFormat.PCM_24000` | The output profile. Import it from `rimelabs_sdk`. |
| `timeout` | Client setting | Seconds, or a `datetime.timedelta`. Pass `None` to disable the overall deadline. |

### Audio formats

Use `AudioFormat.PCM_24000` for PCM or `AudioFormat.MULAW_8000` for mu-law. Read format metadata from `audio.format.encoding`, `audio.format.sample_rate`, and `audio.format.channels`.

### Discover voices and languages

These calls list the English voices and all languages for Mist v3, which is the model of the client:

```python theme={null}
async with Rime(model="mistv3") as client:
    voices = await client.voices.list(language="en")
    languages = await client.languages.list()
    print(voices, languages)
```

Both calls return lists of strings and accept `timeout`. Omit `language` to disable filtering.

### Errors and cancellation

Every SDK error is a `RimeError` subclass from the table in [Completion and errors](#completion-and-errors). Import the classes from `rimelabs_sdk`, and read the request ID from `error.request_id`. The [Python TTS guide](https://github.com/rimelabs/rime-sdk/blob/main/python/docs/tts.md#errors-and-cancellation) shows how to catch the error around the entry point of your application.

Use the `async with` block of the stream, because the SDK cancels unfinished work when the block exits. A cancelled Python task raises `asyncio.CancelledError`. You can also stop work yourself: `await audio.cancel()` stops one operation, and `await client.close()` stops all client work. You can safely repeat both calls. A client belongs to one process and one event loop.

**Node.js / TypeScript**

The [TypeScript package](https://github.com/rimelabs/rime-sdk/tree/main/typescript) has installation steps and examples.

`stream` accepts an async iterable of strings. Do not await the method call. The first iterator read starts work.

### Client options

Select Mist v3 with `new Rime({ model: "mistv3" })`.

| `new Rime({ ... })` option | Default | Meaning |
| - | - | - |
| `apiKey` | `RIME_API_KEY` | The API key. An explicit value overrides the environment. |
| `model` | `"coda"` | The model for speech and discovery |
| `endpoint` | Model's standard endpoint | A custom hostname and optional port for speech and discovery |
| `timeout` | No overall deadline | Positive seconds. `null` disables the overall deadline. |

For a custom deployment, set `endpoint: "host:8443"`.

### Synthesis options

Use `stream(source, { ... })` for an async iterable of strings. Use `synthesize(text, { ... })` for a nonblank string. Both accept the same optional settings:

| Option | Default | Meaning |
| - | - | - |
| `voice` | Model's default voice | A voice name from `client.voices.list()` |
| `language` | `"en"` | The language code |
| `audioFormat` | `AudioFormat.PCM_24000` | The output profile. Import it from `@rimelabs/sdk`. |
| `timeout` | Client setting | Seconds. Pass `null` to disable the overall deadline. |

To use the client setting for one operation, omit its `timeout` or pass `undefined`.

### Audio formats

Use `AudioFormat.PCM_24000` for PCM or `AudioFormat.MULAW_8000` for mu-law. Chunks are `Uint8Array` values. Read format metadata from `audio.format.encoding`, `audio.format.sampleRate`, and `audio.format.channels`.

### Discover voices and languages

List voices and languages while the client is open:

```javascript theme={null}
const voices = await client.voices.list({ language: "en" });
const languages = await client.languages.list();
console.log(voices, languages);
```

Both calls return arrays of strings and accept `timeout`. Omit `language` to disable filtering.

### Errors and cancellation

Every SDK error is a `RimeError` subclass from the table in [Completion and errors](#completion-and-errors). Import the classes from `@rimelabs/sdk`. Check an error with `instanceof`, and read the request ID from `error.requestId`. The [Node.js TTS guide](https://github.com/rimelabs/rime-sdk/blob/main/typescript/docs/tts.md#errors-and-cancellation) has a complete program that reports the error and closes the client.

If you stop early, clean up. When a `for await` loop exits, the SDK cancels the stream. For manual reads, call `await audio.cancel()` in `finally`. Cancellation stops the RPC and limits the cleanup time, but it cannot force your text source to finish an unrelated promise.

`await client.close()` stops all client work. You can safely repeat `audio.cancel()` and `client.close()`, and both objects support `Symbol.asyncDispose`.

**Go**

The [Go SDK](https://github.com/rimelabs/rime-sdk/tree/main/go) needs Go 1.24 or later. It does not need cgo. It supports TTS and [STT](/api-reference/sdk/stt).

Import the module as `rime "github.com/rimelabs/rime-sdk/go"`. The [save example](https://github.com/rimelabs/rime-sdk/tree/main/go/examples/save) of the SDK writes a complete WAV file.

### Configuration

Create a client with `rime.NewClient(rime.Config{})`. It returns `(*rime.Client, error)`. All configuration fields are optional:

| `rime.Config` field | Default | Meaning |
| - | - | - |
| `APIKey` | `RIME_API_KEY` | A nonempty value overrides the environment |
| `Model` | `"coda"` | `"coda"` or `"mistv3"` |
| `Endpoint` | Model's standard endpoint | TLS hostname and optional port, without a scheme or path |
| `Timeout` | `0` | The overall operation duration, as `time.Duration`. Zero disables it. |

### Stream speech

Use `client.TTS.Stream(ctx, source, options)` for incremental text. Use `client.TTS.Synthesize(ctx, text, options)` for a complete, nonblank UTF-8 string. Both return `(*rime.AudioStream, error)` and start work immediately.

A `rime.TextSource` has the signature `func(context.Context) (string, error)`, and the SDK calls it serially, one call at a time. Return each UTF-8 fragment when it arrives, and return `io.EOF` when input ends. The final call can return both text and `io.EOF`, and other errors stop synthesis. The SDK asks the service to collect the fragments into complete sentences, so you do not need to split them.

Pass a non-nil context and `rime.SynthesisOptions{}` to use the defaults:

| `rime.SynthesisOptions` field | Default | Meaning |
| - | - | - |
| `Voice` | Model's default voice | An empty value selects the default. |
| `Language` | `"en"` | An empty value selects the default. |
| `AudioFormat` | `rime.PCM24000` | The output profile |
| `Timeout` | `nil` | A `*time.Duration` override. Nil uses the client setting. |

Read audio with `audio.Recv()`, which returns `([]byte, error)`. Each stream permits one concurrent reader. The output is complete only when `Recv` returns `io.EOF`.

### Audio formats

Use `rime.PCM24000` for PCM or `rime.MULAW8000` for mu-law. Read format metadata with `audio.Format().Encoding()`, `SampleRate()`, and `Channels()`. Send the chunks to your player.

### Timeouts

Use Go durations such as `30 * time.Second`. Negative durations are invalid.

| `Timeout` pointer of an operation | Effect |
| - | - |
| `nil` | Uses the client setting |
| A pointer to zero | Disables the timeout |
| A pointer to a positive duration | Replaces the client setting |

The deadline of your context always applies. It includes pauses between reads.

### Discover voices and languages

While the client is open, list voices and languages. Check each error:

```go theme={null}
voices, err := client.Voices.List(ctx, rime.VoiceListOptions{Language: "en"})
if err != nil {
	return err
}
languages, err := client.Languages.List(ctx, rime.DiscoveryOptions{})
if err != nil {
	return err
}
fmt.Println(voices, languages)
```

Both methods return `([]string, error)`. Each method accepts a `Timeout` pointer in its options. An empty voice `Language` disables filtering.

### Errors and cancellation

Use `errors.As` with `*rime.Error` to read `RequestID` and `Cause`. Errors from your context stay available through error unwrapping. `audio.RequestID()` also returns the request ID, when it is available.

A client can serve concurrent operations. To stop one stream, cancel the context or call `audio.Close()`. To stop all client operations and close the connection, call `client.Close()`. Use `defer` to release both objects, also on early returns. You can safely repeat both `Close` methods.

Your text source must honor its context, because the SDK cannot force a blocked callback in your application to return. Stream cleanup waits at most two seconds for such a source. When the caller interrupts, clear any audio that is already queued in your player.

**Rust**

The [Rust SDK](https://github.com/rimelabs/rime-sdk/tree/main/rust) needs Rust 1.88 or later. It also needs Tokio with I/O and time enabled. It supports TTS and [STT](/api-reference/sdk/stt).

Import the crate as `rimelabs_sdk`.

### Client configuration

Use `Client::builder()`. Set the options, then call `.build()?`. Construction does not send a request.

| Builder method | Default | Meaning |
| - | - | - |
| `.api_key(key)` | `RIME_API_KEY` | An explicit API key |
| `.model(model)` | `Model::Coda` | `Model::Coda` or `Model::MistV3` |
| `.endpoint(host)` | Model's standard endpoint | TLS hostname and optional port, without a scheme or path |
| `.timeout(duration)` | No overall deadline | A positive `std::time::Duration` |

### Text and synthesis options

`client.tts().stream(source, options)` accepts a `Send + 'static` stream of `Result<String, Error>`. Map source errors from your application with `Error::input(error)`. A source that cannot fail still wraps each fragment in `Ok`, for example with `source.map(Ok)`.

`client.tts().synthesize(text, options)` accepts complete text. Call either method without `await`, because both return `Result<AudioStream, Error>` immediately. Read chunks with `StreamExt::next().await`.

Configure either method with `SynthesisOptions::default()` and these builders:

| Method | Default | Meaning |
| - | - | - |
| `.voice(name)` | Model's default voice | A nonblank voice name |
| `.language(tag)` | `"en"` | A nonblank language tag |
| `.audio_format(format)` | `AudioFormat::Pcm24000` | `AudioFormat::Pcm24000` for PCM or `AudioFormat::Mulaw8000` for mu-law |
| `.timeout(value)` | Client setting | `Some(Duration)` overrides it. `None` disables it. Zero is invalid. |

Call `audio.format()` to get the selected profile. Call `audio.request_id()` to get the service request ID, when it is available.

### Discovery and cleanup

Use `client.voices(language).await` and `client.languages().await` to discover voices and languages. Pass `None` to `voices` for no language filter. Both methods return `Result<Vec<String>, Error>`. Discovery allows at most 10 seconds, and if the client timeout is shorter, the client timeout applies.

Call `error.kind()` to get the error category, and call `error.request_id()` to get the service request ID.

When you drop an audio stream, the SDK requests cancellation, and `audio.close().await` also waits for the worker of the stream to stop. `client.close().await` stops operations across all client clones, and when you drop the last client handle, the SDK requests cancellation. Keep the Tokio runtime running until cleanup finishes. When the caller interrupts, clear any audio that is already queued in your application.

The [Rust package reference](https://docs.rs/rimelabs-sdk) documents all public types and methods.

> **Migrate from earlier alpha methods**
>
> The current methods separate complete text from incremental input:
>
> * In Python and TypeScript, `stream` no longer accepts a string.
> * Go no longer provides `StreamSource`.
> * In Rust, synthesis is under `client.tts()`.
>
> | Language | Incremental text | Complete text | First release with these methods |
> | - | - | - | - |
> | Python | `client.tts.stream(source)` | `client.tts.synthesize(text)` | `0.1.0a11` |
> | TypeScript | `client.tts.stream(source)` | `client.tts.synthesize(text)` | `0.1.0-alpha.12` |
> | Go | `client.TTS.Stream(ctx, source, options)` | `client.TTS.Synthesize(ctx, text, options)` | `v0.1.0-alpha.6` |
> | Rust | `client.tts().stream(source, options)` | `client.tts().synthesize(text, options)` | `0.1.0-alpha.3` |


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