# Streaming HTTP Source: https://docs.rime.ai/api-reference/coda/http POST https://users.rime.ai/v1/rime-tts Coda streaming HTTP endpoint: synthesize speech with Rime's flagship model and stream audio back. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The endpoint streams audio in the format you name in the `Accept` header. If `Accept` is missing or a wildcard, the API streams headerless 16-bit PCM, which audio players won't open. If it names a type the API can't stream, the API returns `406` with the list of supported types. ## Audio formats Set the `Accept` header to one of the following values: | Format | Accept Header | Notes | | - | - | - | | Opus (WebM) | `audio/webm;codecs=opus` | Recommended. Smaller files than MP3 at comparable quality. WebM streams natively in browsers. | | Opus (OGG) | `audio/ogg;codecs=opus` | Opus in an OGG container. Smaller files than MP3 at comparable quality. | | MP3 | `audio/mpeg` | Lower compression rate than Opus. Highest compatibility across devices and players. | | WAV | `audio/wav` | Uncompressed. RIFF WAVE header with 16-bit little-endian linear PCM samples. Streams natively in browsers. | | PCM | `audio/L16` | Headerless 16-bit little-endian linear PCM. | | G.711 μ-law | `audio/PCMU` | Headerless stream of audio bytes. | ### Deprecated aliases The API still accepts these for backward compatibility. Use the RFC types above in new code. | Deprecated | Use instead | | - | - | | `audio/mp3` | `audio/mpeg` | | `audio/pcm` | `audio/L16` | | `audio/x-mulaw` | `audio/PCMU` | ## Variable parameters Must be a Coda voice. See the [voice catalog](/docs/voices). The text you'd like spoken. The API accepts up to 1,000 characters per request. Set to `coda` to select the Coda voice lineup. Without it, the API uses Mist v3. If provided, the language must match the language spoken by the provided speaker. Pass a BCP 47 language tag: | Tag | Language | | - | - | | `en` | English | | `es` | Spanish | | `fr` | French | | `pt` | Portuguese | | `de` | German | | `ja` | Japanese | | `ar` | Arabic | | `hi` | Hindi | | `it` | Italian | The 3-letter ISO 639-2 codes that older integrations send (`eng`, `spa`, `fra`, `por`, `ger`, `jpn`, `ara`, `hin`, `ita`) remain accepted, and will stay accepted. See [the voices documentation](/docs/voices) for which speakers support each language. The sampling rate (Hz). The time scaling factor. Accepted range is 0.4 to 2.5. Values outside this range are clamped without an error. Values above 1.0 slow the audio down, and values below 1.0 speed it up. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: audio/webm;codecs=opus' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.webm \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "coda", "speaker": "astra", "lang": "en", "samplingRate": 24000 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "coda", "samplingRate": 24000 } headers = { "Accept": "audio/webm;codecs=opus", "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } with requests.post(url, headers=headers, json=payload, stream=True) as response: response.raise_for_status() with open("output.webm", "wb") as f: for chunk in response.iter_content(chunk_size=4096): if chunk: f.write(chunk) ``` ```javascript JavaScript theme={null} const fs = require("fs"); const options = { method: 'POST', headers: { Accept: 'audio/webm;codecs=opus', Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!","modelId":"coda","samplingRate":24000}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.arrayBuffer()) .then(buffer => { fs.writeFileSync("output.webm", Buffer.from(buffer)); console.log("Audio saved to output.webm"); }) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"coda\",\n \"samplingRate\": 24000\n}", CURLOPT_HTTPHEADER => [ "Accept: audio/webm;codecs=opus", "Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "io" "net/http" "os" "strings" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"coda\",\n \"samplingRate\": 24000\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "audio/webm;codecs=opus") req.Header.Add("Authorization", "Bearer YOUR_API_KEY") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) _ = os.WriteFile("output.webm", body, 0644) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "audio/webm;codecs=opus") .header("Authorization", "Bearer YOUR_API_KEY") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"coda\",\n \"samplingRate\": 24000\n}") .asBytes(); Files.write(Paths.get("output.webm"), response.getBody()); ``` # Websockets Source: https://docs.rime.ai/api-reference/coda/websockets GET wss://users-ws.rime.ai/ws Coda plain-text WebSocket (/ws): send text, receive raw audio bytes. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. Include `modelId=coda` in the connection query. If you omit it, the server routes the request to Mist v3 and speakers outside the Mist v3 catalog can fail with `Speaker not found`. ## Overview Rime's websocket implementation accepts bare text, and responds with audio bytes of the selected format. All synthesis arguments are provided as query parameters when establishing the connection. ## Messages ### Send The messages your client will send to the websocket API will be bare (non-serialized) text. ```example theme={null} This will be converted to audio via websockets ``` ### Receive The messages your client will receive will be raw audio bytes in the audio format specified at connection time. ```example theme={null} ^@^@^@9LAME3.100^AP^@^@^@^@^@^@^@^@^T$^D>"^@^@^@^@<9D>G^N^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@ ``` ## Commands Use these commands to manipulate the stored text buffer. ### `` This clears the current buffer. Used in the event of interruptions. ### `` This forces whatever buffer exists, if any, to be synthesized, and the generated audio to be sent over. ### `` This forces whatever buffer exists, if any, to be synthesized, and for the server to close the connection after sending the generated audio. ## Variable parameters Must be a `coda` voice from the Rime voice catalog. The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set this to `coda`. It is not strictly required, but if you omit it the server defaults to the Mist v3 backend, and speakers outside the Mist v3 catalog fail with a "Speaker not found" error. One of `wav`, `mp3` (or `mpeg`), `ogg` (Opus in OGG), `webm` (Opus in WebM), `pcm` (or `l16`), or `mulaw` (or `pcmu`). Unrecognized values fall back to `wav`. If provided, the language must match the language spoken by the provided speaker. Both the 2-letter ISO 639-1 and the 3-letter ISO 639-2/3 form are accepted: | 639-1 | 639-2/3 | Language | | - | - | - | | `en` | `eng` | English | | `es` | `spa` | Spanish | | `fr` | `fra` | French | | `pt` | `por` | Portuguese | | `de` | `ger` | German | | `ja` | `jpn` | Japanese | | `ar` | `ara` | Arabic | | `hi` | `hin` | Hindi | See the voices documentation for which speakers support each language. The sampling rate in Hz. Any positive integer is accepted; values above the model's native rate are upsampled. Common choices are 8000 (telephony), 16000, 22050, 24000, and 44100. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis Note: For backward compatibility, setting `immediate=true` in query params is equivalent to `segment=immediate`. If a null value is provided, it will default to "bySentence". ```python Python theme={null} import asyncio import websockets import os from dotenv import load_dotenv load_dotenv() api_key = os.environ.get('RIME_API_KEY') if not api_key: raise ValueError("RIME_API_KEY environment variable is not set") FILE_PATH = "coda_ws.wav" class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws?speaker={speaker}&modelId=coda&audioFormat=wav" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_tokens(self, websocket, message): for token in message: await websocket.send(token) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break self.audio_data += audio async def run(self, message): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_tokens(websocket, message), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) message = [ "This ", "is ", "a ", "test ", "of ", "the ", "coda ", "model ", "using ", "websockets ", "and ", "python.", "", ] client = RimeClient("astra", api_key=api_key) asyncio.run(client.run(message)) print(f"Saving audio to {FILE_PATH}") client.save_audio(FILE_PATH) ``` # Websockets JSON Source: https://docs.rime.ai/api-reference/coda/websockets-json GET wss://users-ws.rime.ai/ws3 Coda JSON WebSocket (/ws3): structured events with base64 audio chunks and word-level timestamps. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. Include `modelId=coda` in the connection query. If you omit it, the server routes the request to Mist v3 and speakers outside the Mist v3 catalog can fail with `Speaker not found`. ## Overview In addition to a plaintext websocket implementation, Rime also has an implementation that sends and receives events as JSON objects. Like the other implementation, all synthesis arguments are provided as query parameters when establishing the connection. The WebSocket API buffers inputs up to one of the following punctuation characters: `.`, `?`, `!`. This is most pertinent for the initial messages sent to the API, as synthesis won't begin until there are sufficient tokens to generate audio with natural prosody. After the first synthesis of any given utterance, typically enough time has elapsed that subsequent audio contains multiple clauses, and the buffering becomes largely invisible. ## Messages ### Send #### Text This is the most common message, which contains text for synthesis. schema: ```typescript theme={null} type TextMessage = { text: string, contextId?: string, } ``` examples: ```json theme={null} { "text": "this is the minimum text message." } { "text": "this is a text message with a context id.", "contextId": "159495B1-5C81-4C73-A51A-9CE10A08239E" } ``` Context IDs can be provided, which will be attached to subsequent messages that the server sends back to the client. Rime will not maintain multiple simultaneous context IDs. The events will contain the most recent context ID at the time that audio was requested. In the above examples, even if both messages are received by the server before it sends any audio, the audio response for the first sentence will be tagged with `contextId: null`, and the audio for the second will be tagged with its UUID. #### Clear Your client can clear out the accumulated buffer, which is useful in the case of interruptions. ```json theme={null} { "operation": "clear" } ``` #### Flush This forces whatever buffer exists, if any, to be synthesized, and the generated audio to be sent over. ```json theme={null} { "operation": "flush" } ``` #### EOS At times, your client would like to generate audio for whatever remains in the buffer, and then have the connection immediately closed. ```json theme={null} { "operation" : "eos" } ``` ### Receive #### Chunk The most common event will be the audio chunk. ```typescript theme={null} type Base64String = string type AudioChunkEvent = { type: "chunk", data: Base64String, contextId: string | null, } ``` The audio will be a base64 encoded chunk of audio bytes in the audio format specified when the connection was established. If you provided any context id when sending the relevant text, it'll be included here. #### Timestamps Word-level timestamps are emitted alongside the audio chunks so the client can tell exactly which words have been spoken at any point. This is especially useful for handling interruptions: when the user starts talking over the output, you can map the playback position back to the last word that was actually heard. Timestamps are emitted only when `lang` is `en`/`eng` or `es`/`spa`, or when `lang` is omitted. Requests in any other language receive `chunk` and `done` events with no `timestamps` event and no error (this includes fr, de, ja, pt, ar, and hi). Do not block playback while waiting for a timestamps event. ```typescript theme={null} type TimestampsEvent = { type: "timestamps", word_timestamps: { words: string[], start: number[], end: number[], }, contextId: string | null, } ``` The three arrays inside `word_timestamps` are the same length and index-aligned: for a given index `i`, `words[i]` is spoken from `start[i]` to `end[i]`. Times are in seconds, measured from the beginning of the audio for the current synthesis. If a context id was attached to the text that produced this audio, it is included on the event. Example payload: ```json theme={null} { "type": "timestamps", "word_timestamps": { "words": ["Hello", "from", "Coda", "over", "JSON", "websockets."], "start": [0, 0.36106, 0.54159, 0.72212, 0.90265, 1.08318], "end": [0.36106, 0.54159, 0.72212, 0.90265, 1.08318, 2.88848] }, "contextId": null } ``` #### Done After the last audio chunk for a synthesis batch has been sent, the server emits a `done` event. This signals that the current synthesis is fully complete. If the client sends more text and triggers further synthesis, another `done` will follow. ```typescript theme={null} type DoneEvent = { type: "done", contextId: string | null, } ``` When exactly `done` fires depends on the `segment` setting. See [Segmentation and behavior settings](/docs/websockets-segment) for full details. #### Error In the event of a malformed or unexpected input, the server will immediately respond with an error message. The server will *not* close the connection, and will still accept subsequent well-formed messages. It's up to the client to decide if it wants to close upon receiving an error. ```typescript theme={null} type ErrorEvent = { type: "error", message: string, } ``` ## Variable parameters Must be a `coda` voice from the Rime voice catalog. The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set this to `coda`. It is not strictly required, but if you omit it the server defaults to the Mist v3 backend, and speakers outside the Mist v3 catalog fail with a "Speaker not found" error. One of `wav`, `mp3` (or `mpeg`), `ogg` (Opus in OGG), `webm` (Opus in WebM), `pcm` (or `l16`), or `mulaw` (or `pcmu`). Unrecognized values fall back to `wav`. If provided, the language must match the language spoken by the provided speaker. Pass a BCP 47 language tag: | Tag | Language | | - | - | | `en` | English | | `es` | Spanish | | `fr` | French | | `pt` | Portuguese | | `de` | German | | `ja` | Japanese | | `ar` | Arabic | | `hi` | Hindi | | `it` | Italian | The 3-letter ISO 639-2 codes that older integrations send (`eng`, `spa`, `fra`, `por`, `ger`, `jpn`, `ara`, `hin`, `ita`) remain accepted, and will stay accepted. See the voices documentation for which speakers support each language. The sampling rate in Hz. Any positive integer is accepted; values above the model's native rate are upsampled. Common choices are 8000 (telephony), 16000, 22050, 24000, and 44100. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis Note: For backward compatibility, setting `immediate=true` in query params is equivalent to `segment=immediate`. If a null value is provided, it will default to "bySentence". ```python Python theme={null} import asyncio import json import websockets import base64 class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws3?speaker={speaker}&modelId=coda&audioFormat=mp3" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_messages(self, websocket, messages): for message in messages: await websocket.send(json.dumps(message)) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break message = json.loads(audio) if message['type'] == 'chunk': self.audio_data += base64.b64decode(message['data']) if message['type'] == 'timestamps': print("Rime model pronounced the words...\n") for w, t in zip(message['word_timestamps']['words'], message['word_timestamps']['start']): print(f"'{w}' at time {t}") async def run(self, messages): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_messages(websocket, messages), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) print(f"\n Audio saved at {file_path}") message = [ {"text": "This "}, {"text": "is "}, {"text": "a "}, {"text": "test "}, {"operation":"clear"}, {"text": "This "}, {"text": "is "}, {"text": "an "}, {"text": "incomplete "}, {"text": "sentence "}, {"operation": "eos"}, ] client = RimeClient("astra", api_key="xxx") asyncio.run(client.run(message)) client.save_audio("output.mp3") ``` # List Voice Details Source: https://docs.rime.ai/api-reference/data/voice-details GET https://users.rime.ai/data/voices/voice_details.json Voice metadata endpoint: list every Rime voice with demographic and model details. This is a public endpoint, so you don't need an `Authorization` header or API key. The response can include legacy Arcana records and models hosted outside the Rime cloud API. Their presence does not mean the model is available through Rime cloud. Use [Coda or Mist](/docs/models) for cloud requests. ## View in browser [https://users.rime.ai/data/voices/voice\_details.json](https://users.rime.ai/data/voices/voice_details.json) ## Description The demographic fields are based on subjective assessment and are a general guide to each voice. Use them to narrow your choice. The only values you pass in a request are `speaker`, `modelId`, and `lang`. See [Finding a Voice](/docs/voices) to choose a voice, and [Explanation of fields](#explanation-of-fields) for each field. ## Example structure ```json theme={null} [ { "speaker": "astra", "gender": "Female", "age": "Young Adult", "country": "US", "dialect": "Standard", "demographic": "White", "genre": [ "Conversational, Customer Support, Narration" ], "modelId": "coda", "language": "English", "lang": "eng", "flagship": true }, { "speaker": "cove", "gender": "Female", "age": "Young Adult", "country": "US", "dialect": "African American", "demographic": "Black", "genre": [ "Customer Support" ], "modelId": "mistv3", "language": "English", "lang": "eng", "flagship": true }, // and more... ] ``` ## Explanation of fields The response is an array with one object per voice. Each object contains the following fields: * `speaker`: The voice name. Pass it as `speaker` in a request. * `gender`: Indicates the gender of the voice. * `age`: Describes the age group of the voice. * `country`: The country that the voice is associated with, typically representing the accent or regional dialect. * `dialect`: More specific than country, this field can indicate a particular area within a country. * `demographic`: Describes the demographic group the voice represents. * `genre`: An array of genres that the voice is suitable for, such as `Conversational`. * `language`: The language the voice speaks. * `lang`: The value to pass as `lang` so the voice speaks its language. * `modelId`: The model the voice is available under. Pass it as `modelId` in a request. * `flagship`: `true` for featured voices. # List All Voices Source: https://docs.rime.ai/api-reference/data/voices-v2 GET https://users.rime.ai/data/voices/all-v2.json List every Rime voice, keyed by modelId and language. This is a public endpoint, so you don't need an `Authorization` header or API key. The response can include legacy Arcana records and models hosted outside the Rime cloud API. Their presence does not mean the model is available through Rime cloud. Use [Coda or Mist](/docs/models) for cloud requests. ## View in browser [https://users.rime.ai/data/voices/all-v2.json](https://users.rime.ai/data/voices/all-v2.json) ## Example structure ```json theme={null} { "coda": { "eng": [ "astra", "albion", // ...and more... ], "spa": [ "alba", "celestino", // ...and more... ] }, "mistv3": { "eng": [ "alexis", "astra", // ...and more... ], "spa": [ "diego", "isa", // ...and more... ] } } ``` ## Explanation The response is keyed by `modelId`, then by ISO 639-2 language code, and each entry lists the `speaker` values for that model and language. For current cloud models, pass the top-level key as `modelId` in a request to the [Rime TTS APIs](/docs/api-reference). # Streaming HTTP Source: https://docs.rime.ai/api-reference/mistv2/http POST https://users.rime.ai/v1/rime-tts Mist v2 streaming HTTP endpoint. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The endpoint streams audio in the format you name in the `Accept` header. If `Accept` doesn't name a streamable audio type, for example because it's missing or set to `application/json`, Mist v2 returns the legacy JSON envelope instead, as described in [MP3 over JSON](/api-reference/mistv2/json-mp3). ## Audio formats Set the `Accept` header to one of the following values: | Format | Accept Header | Default Sampling Rate | Notes | | - | - | - | - | | MP3 | `audio/mpeg` | 22050 | | | PCM | `audio/L16` | 16000 | Headerless 16-bit little-endian linear PCM. | | G.711 μ-law | `audio/PCMU` | 8000 | Headerless stream of audio bytes. | ### Deprecated aliases The API still accepts these for backward compatibility. Use the RFC types above in new code. | Deprecated | Use instead | | - | - | | `audio/mp3` | `audio/mpeg` | | `audio/pcm` | `audio/L16` | | `audio/x-mulaw` | `audio/PCMU` | ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set to `mistv2`. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default depends on format (see table above). Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: audio/mpeg' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.mp3 \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "samplingRate": 22050, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "mistv2", "lang": "eng", "samplingRate": 22050, "speedAlpha": 1.0 } headers = { "Accept": "audio/mpeg", "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } with requests.post(url, headers=headers, json=payload, stream=True) as response: response.raise_for_status() with open("output.mp3", "wb") as f: for chunk in response.iter_content(chunk_size=4096): if chunk: f.write(chunk) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'audio/mpeg', Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!","modelId":"mistv2","lang":"eng","samplingRate":22050,"speedAlpha":1.0}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.arrayBuffer()) .then(buffer => { require("fs").writeFileSync("output.mp3", Buffer.from(buffer)); console.log("Audio saved to output.mp3"); }) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0\n}", CURLOPT_HTTPHEADER => [ "Accept: audio/mpeg", "Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "io" "net/http" "os" "strings" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "audio/mpeg") req.Header.Add("Authorization", "Bearer YOUR_API_KEY") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) _ = os.WriteFile("output.mp3", body, 0644) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "audio/mpeg") .header("Authorization", "Bearer YOUR_API_KEY") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0\n}") .asString(); ``` # MP3 over JSON Source: https://docs.rime.ai/api-reference/mistv2/json-mp3 POST https://users.rime.ai/v1/rime-tts Mist v2 non-streaming endpoint that returns base64 MP3 audio inside a JSON envelope. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The API returns a single JSON object, `{"audioContent": "..."}`, whose `audioContent` field holds base64-encoded MP3 audio. Decode it before you save or play it. Only Mist v1 and Mist v2 return this envelope, and only when `Accept` doesn't name a streamable audio type, which is why the examples send `application/json`. The response arrives after synthesis finishes, so use [streaming HTTP](/api-reference/mistv2/http) if you want playback to start sooner. ## Fixed parameters ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set to `mistv2`. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: For text "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default: 22050 Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.json \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "audioFormat": "mp3", "inlineSpeedAlpha": "0.5, 3", "noTextNormalization": false, "pauseBetweenBrackets": false, "phonemizeBetweenBrackets": false, "samplingRate": 22050, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "mistv2", "lang": "eng", "audioFormat": "mp3", "samplingRate": 22050, "speedAlpha": 1.0, "noTextNormalization": False } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!", "modelId": "mistv2", "lang": "eng", "audioFormat": "mp3", "samplingRate":22050,"speedAlpha":1.0,"noTextNormalization":false}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\":\"mistv2\",\n \"lang\":\"eng\",\n \"audioFormat\": \"mp3\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"modelId\": \"mistv2\",\n \"text\": \"Hello from Rime!\",\n \"lang\": \"eng\",\n \"audioFormat\": \"mp3\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"mp3\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") .asString(); ``` # μ-law over JSON Source: https://docs.rime.ai/api-reference/mistv2/json-mulaw POST https://users.rime.ai/v1/rime-tts Mist v2 non-streaming endpoint that returns base64 G.711 μ-law audio inside a JSON envelope. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The API returns a single JSON object, `{"audioContent": "..."}`, whose `audioContent` field holds base64-encoded G.711 μ-law audio. Decode it before you save or play it. Only Mist v1 and Mist v2 return this envelope, and only when `Accept` doesn't name a streamable audio type, which is why the examples send `application/json`. The response arrives after synthesis finishes, so use [streaming HTTP](/api-reference/mistv2/http) if you want playback to start sooner. ## Fixed parameters ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set to `mistv2`. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.json \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "audioFormat": "mulaw", "inlineSpeedAlpha": "0.5, 3", "noTextNormalization": false, "pauseBetweenBrackets": false, "phonemizeBetweenBrackets": false, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "mistv2", "lang": "eng", "audioFormat": "mulaw", "speedAlpha": 1.0, "noTextNormalization": False, "pauseBetweenBrackets": False, "phonemizeBetweenBrackets": False } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!","modelId":"mistv2","lang": "eng","audioFormat": "mulaw","speedAlpha":1.0,"noTextNormalization":false}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\":\"eng\",\n \"audioFormat\": \"mulaw\",\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"mulaw\",\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"mulaw\",\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") .asString(); ``` # OGG over JSON Source: https://docs.rime.ai/api-reference/mistv2/json-ogg POST https://users.rime.ai/v1/rime-tts Mist v2 non-streaming endpoint that returns base64 Opus/Ogg audio inside a JSON envelope. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The API returns a single JSON object, `{"audioContent": "..."}`, whose `audioContent` field holds base64-encoded Opus audio in an Ogg container. Decode it before you save or play it. Only Mist v1 and Mist v2 return this envelope, and only when `Accept` doesn't name a streamable audio type, which is why the examples send `application/json`. The response arrives after synthesis finishes, so use [streaming HTTP](/api-reference/mistv2/http) if you want playback to start sooner. ## Fixed parameters ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. Must be one of `8000`, `12000`, `16000`, or `24000` Set to `mistv2`. Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.json \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "audioFormat": "ogg", "inlineSpeedAlpha": "0.5, 3", "noTextNormalization": false, "pauseBetweenBrackets": false, "phonemizeBetweenBrackets": false, "samplingRate": 24000, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "mistv2", "lang": "eng", "audioFormat": "ogg", "samplingRate": 24000, "speedAlpha": 1.0, "noTextNormalization": False, "pauseBetweenBrackets": False, "phonemizeBetweenBrackets": False } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!","modelId":"mistv2", "lang": "eng", "audioFormat": "ogg","samplingRate":24000,"speedAlpha":1.0,"noTextNormalization":false}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\":\"eng\",\n \"audioFormat\": \"ogg\",\n \"samplingRate\": 24000,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"ogg\",\n \"samplingRate\": 24000,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"ogg\",\n \"samplingRate\": 24000,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") .asString(); ``` # WAV over JSON Source: https://docs.rime.ai/api-reference/mistv2/json-wav POST https://users.rime.ai/v1/rime-tts Mist v2 non-streaming endpoint that returns base64 WAV audio inside a JSON envelope. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The API returns a single JSON object, `{"audioContent": "..."}`, whose `audioContent` field holds base64-encoded WAV audio. Decode it before you save or play it. Only Mist v1 and Mist v2 return this envelope, and only when `Accept` doesn't name a streamable audio type, which is why the examples send `application/json`. The response arrives after synthesis finishes, so use [streaming HTTP](/api-reference/mistv2/http) if you want playback to start sooner. ## Fixed parameters ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). Set to `mistv2`. When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default: 22050 Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.json \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "audioFormat": "wav", "inlineSpeedAlpha": "0.5, 3", "noTextNormalization": false, "pauseBetweenBrackets": false, "phonemizeBetweenBrackets": false, "samplingRate": 22050, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "astra", "text": "Hello from Rime!", "modelId": "mistv2", "lang": "eng", "audioFormat": "wav", "samplingRate": 22050, "speedAlpha": 1.0, "noTextNormalization": False, "phonemizeBetweenBrackets": False, "pauseBetweenBrackets": False } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"speaker":"astra","text":"Hello from Rime!","modelId":"mistv2", "lang": "eng", "audioFormat": "wav","samplingRate":22050,"speedAlpha":1.0,"noTextNormalization":false}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\":\"eng\",\n \"audioFormat\": \"wav\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv2\",\n \"lang\": \"eng\",\n \"audioFormat\": \"wav\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"astra\",\n \"text\": \"Hello from Rime!\",\n \"audioFormat\": \"wav\", \n \"modelId\": \"mistv2\", \n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") .asString(); ``` # Server-sent Events Source: https://docs.rime.ai/api-reference/mistv2/sse POST https://users.rime.ai/v1/rime-tts Mist v2 Server-Sent Events endpoint for streaming audio chunks over text/event-stream. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. When you set `Accept: text/event-stream`, the `/v1/rime-tts` route streams the response as server-sent events. SSE is specific to Mist v2, so use streaming HTTP or WebSockets for other models. ## Fixed headers ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set to `mistv2`. One of `mp3`, `mulaw`, or `pcm` If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default: 22050 Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. ## Example output ``` event: chunk data: {"data": "vv+t/7j/sv+8/8j/zv/U/9T/z//P/87/yv/J/8n/0//X/9r/5f/p/+//8f/y//b/8f/x//P/9v/+/wAAAAD3/+3/7v/v//X/+P/0//r/8v/r//D/8P/x/+v/7P/1//D/7//0//b/9//7//r/8//5//7/9//8/wYABwAHAAgADAAKAAEA///8//n/9P/w/+//7P/p/+L/5f/l/+D/6v/s/+//9f/r/+z/8P/u/+//8//t/+j/7//t/9//3//f/97/4P/f/+D/4P/k/+P/3v/f/9//4//p/+b/5f/l/9z/4f/p/+H/5//m/+H/8P/x/+7/9f/9//z/8//2//r/9v/w/+//8f/p/+P/4f/d/9z/2//Z/9r/3P/e/9z/4P/k/+L/4//f/9z/2f/a/9v/0v/N/8n/yf/J/8D/tv+z/7f/s/+x/7f/sv+x/8D/xP/C/8b/yv/S/9H/xf/D/8n/zv/S/8//0P/X/9D/z//X/9T/0P/L/8X/yP/S/9X/0f/L/83/1f/b/+D/2//W/9X/0P/U/9j/0P/U/9n/2v/i/+v/8v/s/9z/2f/U/8f/yP/M/8n/yf/P/9D/yf/Q/8r/xP/Q/8v/zf/T/9L/2v/Z/9z/5v/o/+j/6f/o/+b/5//o//H/+P/z//L/7//o/+T/5P/m/+3/7//v//P/6//p//P/8P/p/+X/4//j/+X/6P/l/+X/7P/o/9//5P/h/9n/2//b/93/5f/g/9r/0//L/8//yf++/7//vP+8/8H/wf/C/8H/v/+6/7T/sf+u/63/qv+t/6//q/+t/6v/p/+l/6T/pf+t/7L/r/+u/7f/vf+7/7r/vf+6/7v/u//A/83/yf/I/w=="} event: chunk data: {"data": "zP/J/8P/uP+8/7r/tf+//7j/tP+3/7X/uv+//8H/x//F/8L/yf/J/8n/y//H/8P/vf+7/73/xv/J/8r/z//N/8//yf/D/8P/xf/M/8z/yP/G/8H/vP+//8X/xf/J/8//0P/P/9T/2P/Y/9v/2f/Z/9//2v/d/+H/3f/d/9v/0//U/9j/1v/Z/+L/6v/s/+7/6v/g/9v/1//P/8n/x//I/8f/v/+3/7X/uP+7/7T/tP+6/7T/sP+6/8P/zP/Q/8z/z//T/9j/4f/c/+D/5v/d/+X/7v/o/+n/6v/o/+j/6P/i/9z/2//f/9z/3P/e/9j/2f/g/+z/7v/q/+n/5v/r//L/8v/n/9z/5P/u/+3/6f/p/+//7//o/+r/9P/v//H/+P/t/+//9f/2//T/8P/1//X/9f/+/wcABAAIABIAFAAYABcAEwAYABgAGwAlACgAKAAoACQAJAAnACYAJwAoACAAGwAiACYAKQArACsALwAuACkAKwAqACkAJQAXABcAGAAQABIAGAAaABgAHgAlACIAJAAjACUAKwAkACEAJAAjACYAKwAzADUAMAAyADgAMwArAC8AMgA0ADgAOAA6ADYAPABCAEEARABHAEQAQwBDAD8APQBDAEUARgBDADsAPgBBADgAPABDAD4ARQBMAEkARwBCAEIAQwBFAEcAQABCAEcAPgBBAEYAQwA7ADYAPQBDAEcARABEAEgARwBOAE0ARwBOAE0ASABEADgANQA2ADoAQAA5ADIANQA0ADUAOQA5ADwAQgBDAEIARQBGAEIAPgA9AD4AOwA7ADsAQwBJAEYAVQBaAFUAUwBNAFIAVgBQAE8AUgBYAFQATQBQAA=="} event: timestamps data: {"word_timestamps": {"words": ["over", "the", "last", "six", "months", ",", "there", "has", "been", "a", "lot", "of", "talk", "about", "the", "future", "of", "theatrical", "exhibition"], "start": [0, 0.624, 0.816, 1.12, 1.52, 2.08, 2.3, 2.496, 2.7, 2.896, 3.024, 3.232, 3.408, 3.664, 4.0, 4.192, 4.608, 4.768, 5.456], "end": [0.624, 0.816, 1.12, 1.52, 2.08, 2.304, 2.496, 2.704, 2.896, 3.024, 3.232, 3.408, 3.664, 4.0, 4.192, 4.608, 4.768, 5.456, 6.672]}} event: done data: {"done": true} ``` `chunk` events carry base64-encoded audio in `data`. Decode each one and append the bytes in order to rebuild the audio. The `timestamps` event gives word-level timings, and `done` marks the end of the stream, so stop reading when it arrives. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: text/event-stream' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.txt \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv2", "speaker": "astra", "lang": "eng", "inlineSpeedAlpha": "0.5, 3", "noTextNormalization": false, "pauseBetweenBrackets": false, "phonemizeBetweenBrackets": false, "samplingRate": 22050, "speedAlpha": 1.0 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "", "text": "", "modelId": "", "lang": "eng", "samplingRate": 22050, "speedAlpha": 1.0, "noTextNormalization": False, "pauseBetweenBrackets": False, "phonemizeBetweenBrackets": False } headers = { "Accept": "text/event-stream", "Authorization": "Bearer ", "Content-Type": "application/json" } # Use stream=True to handle streaming response response = requests.request("POST", url, json=payload, headers=headers, stream=True) # Check if the request was successful if response.status_code == 200: with open("audio_output.mp3", "wb") as f: for chunk in response.iter_content(chunk_size=1024): if chunk: f.write(chunk) else: print("Error:", response.status_code) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'text/event-stream', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"speaker":"","text":"","modelId":"","lang": "eng", "samplingRate":22050,"speedAlpha":1.0,"noTextNormalization":false}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.text()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"\",\n \"text\": \"\",\n \"modelId\": \"\",\n \"lang\":\"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}", CURLOPT_HTTPHEADER => [ "Accept: text/event-stream", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"\",\n \"text\": \"\",\n \"modelId\": \"\",\n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "text/event-stream") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "text/event-stream") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"\",\n \"text\": \"\",\n \"modelId\": \"\",\n \"lang\": \"eng\",\n \"samplingRate\": 22050,\n \"speedAlpha\": 1.0,\n \"noTextNormalization\": false\n}") .asString(); ``` # Websockets Source: https://docs.rime.ai/api-reference/mistv2/websockets GET wss://users-ws.rime.ai/ws Mist v2 plain-text WebSocket (/ws): send text, receive raw audio bytes. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This WebSocket accepts plain text and returns raw audio bytes in the format you set with `audioFormat`. You pass every synthesis parameter as a query parameter when you open the connection, and those settings apply for the life of the connection. The API buffers input until it detects a sentence boundary, typically at `.`, `?`, or `!`, so synthesis starts once it has enough text for natural prosody. The wait is most noticeable on the first sentence. After that, later text usually arrives while earlier audio is still playing, and the buffering becomes largely invisible. To change when synthesis starts, set `segment`. ## Messages ### Send Send bare text, not JSON. ```example theme={null} This will be converted to audio via websockets ``` ### Receive Your client receives raw audio bytes in the `audioFormat` set at connection time. Append the messages in order to rebuild the audio. ```example theme={null} ^@^@^@9LAME3.100^AP^@^@^@^@^@^@^@^@^T$^D>"^@^@^@^@<9D>G^N^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@ ``` ## Commands Send these strings as text messages to control the buffer. ### `` Discards buffered text that hasn't been synthesized yet. Send it when the user interrupts. It doesn't cancel a synthesis already in progress, so stop playback in your client and drop any audio that still arrives. ### `` Synthesizes whatever text is buffered, without waiting for a sentence boundary, and sends the audio. ### `` Synthesizes whatever text is buffered, sends the audio, and then the server closes the connection. ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). Set to `mistv2`. One of `mp3`, `mulaw`, or `pcm` If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default: 22050 Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis Note: For backward compatibility, setting `immediate=true` in query params is equivalent to `segment=immediate`. If a null value is provided, it will default to "bySentence". ```python Python theme={null} import asyncio import websockets class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws?speaker={speaker}&modelId=mistv2&audioFormat=mp3" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_tokens(self, websocket, message): for token in message: await websocket.send(token) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break self.audio_data += audio async def run(self, message): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_tokens(websocket, message), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) message = [ "This ", "is ", "a ", "test ", "", "This ", "is ", "a ", "sentence, ", "that ", "will ", "produce ", "audio ", "across ", "two ", "messages.", "", ] client = RimeClient("cove", api_key="xxx") asyncio.run(client.run(message)) client.save_audio("output.mp3") ``` # Websockets JSON Source: https://docs.rime.ai/api-reference/mistv2/websockets-json GET wss://users-ws.rime.ai/ws2 Mist v2 JSON WebSocket (/ws2): structured events with base64 audio chunks and word-level timestamps. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This WebSocket sends and receives JSON messages. Compared with the [plain-text WebSocket](/api-reference/mistv2/websockets), it adds word-level timestamps, a `done` event after each synthesis, and `contextId` tagging. You pass every synthesis parameter as a query parameter when you open the connection, and those settings apply for the life of the connection. The API buffers input until it detects a sentence boundary, typically at `.`, `?`, or `!`, so synthesis starts once it has enough text for natural prosody. The wait is most noticeable on the first sentence. After that, later text usually arrives while earlier audio is still playing, and the buffering becomes largely invisible. To change when synthesis starts, set `segment`. ## Messages ### Send #### Text Sends text for synthesis. This is the message your client sends most often. schema: ```typescript theme={null} type TextMessage = { text: string, contextId?: string, } ``` examples: ```json theme={null} { "text": "this is the minimum text message." } { "text": "this is a text message with a context id.", "contextId": "159495B1-5C81-4C73-A51A-9CE10A08239E" } ``` If you set `contextId`, the server attaches it to the events it sends back for that text. The server tracks one context ID at a time, and each event carries the most recent context ID at the time its audio was requested. In the examples above, even if the server receives both messages before it sends any audio, the first sentence's audio is tagged `contextId: null` and the second sentence's audio is tagged with its UUID. #### Clear Discards buffered text that hasn't been synthesized yet. Send it when the user interrupts. It doesn't cancel a synthesis already in progress, so stop playback in your client and drop any audio that still arrives. ```json theme={null} { "operation": "clear" } ``` #### Flush Synthesizes whatever text is buffered, without waiting for a sentence boundary, and sends the audio. ```json theme={null} { "operation": "flush" } ``` #### EOS Synthesizes whatever text is buffered, sends the audio, and then the server closes the connection. ```json theme={null} { "operation" : "eos" } ``` ### Receive #### Chunk Carries a piece of the synthesized audio. This is the event your client receives most often. ```typescript theme={null} type Base64String = string type AudioChunkEvent = { type: "chunk", data: Base64String, contextId: string | null, } ``` `data` holds base64-encoded audio in the `audioFormat` set at connection time. Decode each chunk and append the bytes in order to rebuild the audio. If the text that produced this audio had a `contextId`, the event includes it. #### Timestamps The server sends word-level timestamps alongside the audio chunks, so your client can tell which words have been spoken at any point. When the user talks over the output, map the playback position back to the last word they actually heard. Timestamps are emitted only when `lang` is `en`/`eng` or `es`/`spa`, or when `lang` is omitted. Requests in any other language receive `chunk` and `done` events with no `timestamps` event and no error. Don't block playback while waiting for a timestamps event. ```typescript theme={null} type TimestampsEvent = { type: "timestamps", word_timestamps: { words: string[], start: number[], end: number[], }, contextId: string | null, } ``` The three arrays inside `word_timestamps` are the same length and index-aligned: for a given index `i`, `words[i]` is spoken from `start[i]` to `end[i]`. Times are in seconds, measured from the beginning of the audio for the current synthesis. If a context id was attached to the text that produced this audio, it is included on the event. Example payload: ```json theme={null} { "type": "timestamps", "word_timestamps": { "words": ["Hello", "from", "a", "timestamps", "probe", "."], "start": [0, 0.35991, 0.51084, 0.59211, 1.10295, 1.41642], "end": [0.35991, 0.51084, 0.59211, 1.10295, 1.41642, 1.5093] }, "contextId": null } ``` #### Done After the last audio chunk for a synthesis batch has been sent, the server emits a `done` event. This signals that the current synthesis is fully complete. If the client sends more text and triggers further synthesis, another `done` will follow. The `eos` operation emits a final `done` for any remaining buffered content before the server closes the connection. If the buffer is already empty, the server closes without sending a `done`. ```typescript theme={null} type DoneEvent = { type: "done", done: true, contextId: string | null, } ``` On `/ws2`, the `done` event carries an extra boolean `done: true` field in addition to `type: "done"`. On `/ws3` the event contains only `type` and `contextId`. Match on `type === "done"` to handle both. When exactly `done` fires depends on the `segment` setting. See [Segmentation and behavior settings](/docs/websockets-segment) for full details. #### Error If a message is malformed or unexpected, the server responds immediately with an `error` event. The server does *not* close the connection and keeps accepting well-formed messages, so your client decides whether to close it. ```typescript theme={null} type ErrorEvent = { type: "error", message: string, } ``` ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). Set to `mistv2`. One of `mp3`, `mulaw`, or `pcm` If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds.
Example: "Hi. \<200> I'd love to have a conversation with you." adds a 200ms pause between the first and second sentences.
When set to true, you can specify the phonemes for a word enclosed in curly brackets.
Example: "\{h'El.o} World" pronounces "Hello" with the phonemes you supplied. Learn more about [custom pronunciation](/docs/custom-pronunciation).
Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. The value, if provided, must be between 4000 and 44100. Default: 22050 Adjusts the speed of speech. Lower than 1.0 is faster and higher than 1.0 is slower. *Note: this is the legacy Mist v2 convention. Coda and Mist v3 invert it, so for those models higher than 1.0 is faster.* **mist/mistv2 only.** Skips text normalization before synthesis. This reduces latency, but digits and abbreviations reach the model unexpanded and may be mispronounced. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis Note: For backward compatibility, setting `immediate=true` in query params is equivalent to `segment=immediate`. If a null value is provided, it will default to "bySentence". ```python Python theme={null} import asyncio import json import websockets import base64 class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws2?speaker={speaker}&modelId=mistv2&audioFormat=mp3" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_messages(self, websocket, messages): for message in messages: await websocket.send(json.dumps(message)) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break message = json.loads(audio) if message['type'] == 'chunk': self.audio_data += base64.b64decode(message['data']) if message['type'] == 'timestamps': print("Rime model pronounced the words...\n") for w, t in zip(message['word_timestamps']['words'], message['word_timestamps']['start']): print(f"'{w}' at time {t}") async def run(self, messages): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_messages(websocket, messages), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) print(f"\n Audio saved at {file_path}") message = [ {"text": "This "}, {"text": "is "}, {"text": "a "}, {"text": "test "}, {"operation":"clear"}, {"text": "This "}, {"text": "is "}, {"text": "an "}, {"text": "incomplete "}, {"text": "sentence "}, {"operation": "eos"}, ] client = RimeClient("cove", api_key="xxx") asyncio.run(client.run(message)) client.save_audio("output.mp3") ``` # Streaming HTTP Source: https://docs.rime.ai/api-reference/mistv3/http POST https://users.rime.ai/v1/rime-tts Mist v3 streaming HTTP endpoint: low-latency TTS with the updated Mist engine. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. The endpoint streams audio in the format you name in the `Accept` header. If `Accept` is missing or a wildcard, the API streams headerless 16-bit PCM, which audio players won't open. If it names a type the API can't stream, the API returns `406` with the list of supported types. ## Audio formats Set the `Accept` header to one of the following values: | Format | Accept Header | Notes | | - | - | - | | Opus (WebM) | `audio/webm;codecs=opus` | Recommended. Smaller files than MP3 at comparable quality. WebM streams natively in browsers. | | Opus (OGG) | `audio/ogg;codecs=opus` | Opus in an OGG container. Smaller files than MP3 at comparable quality. | | MP3 | `audio/mpeg` | Lower compression rate than Opus. Highest compatibility across devices and players. | | WAV | `audio/wav` | Uncompressed. RIFF WAVE header with 16-bit little-endian linear PCM samples. Streams natively in browsers. | | PCM | `audio/L16` | Headerless 16-bit little-endian linear PCM. | | G.711 μ-law | `audio/PCMU` | Headerless stream of audio bytes. | ### Deprecated aliases The API still accepts these for backward compatibility. Use the RFC types above in new code. | Deprecated | Use instead | | - | - | | `audio/mp3` | `audio/mpeg` | | `audio/pcm` | `audio/L16` | | `audio/x-mulaw` | `audio/PCMU` | ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). The text you'd like spoken. Character limit per request is 1,000 via the API and in the dashboard UI. Set to `mistv3`. The API also uses Mist v3 when `modelId` is omitted, but setting it keeps the request from depending on that default. The sampling rate (Hz). The time scaling factor. Accepted range is 0.4 to 2.5. Values outside this range are clamped without an error. Values above 1.0 slow the audio down, and values below 1.0 speed it up. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds. Example: `Hi. <200> I'd love to have a conversation with you.` adds a 200ms pause. Learn more about [custom pauses](/docs/custom-pauses). Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Accept: audio/webm;codecs=opus' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --output output.webm \ --fail \ --data '{ "text": "Hello from Rime!", "modelId": "mistv3", "speaker": "cove", "lang": "en", "samplingRate": 24000 }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/v1/rime-tts" payload = { "speaker": "cove", "text": "Hello from Rime!", "modelId": "mistv3", "samplingRate": 24000 } headers = { "Accept": "audio/webm;codecs=opus", "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } with requests.post(url, headers=headers, json=payload, stream=True) as response: response.raise_for_status() with open("output.webm", "wb") as f: for chunk in response.iter_content(chunk_size=4096): if chunk: f.write(chunk) ``` ```javascript JavaScript theme={null} const fs = require("fs"); const options = { method: 'POST', headers: { Accept: 'audio/webm;codecs=opus', Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: '{"speaker":"cove","text":"Hello from Rime!","modelId":"mistv3","samplingRate":24000}' }; fetch('https://users.rime.ai/v1/rime-tts', options) .then(response => response.arrayBuffer()) .then(buffer => { fs.writeFileSync("output.webm", Buffer.from(buffer)); console.log("Audio saved to output.webm"); }) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/v1/rime-tts", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"speaker\": \"cove\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv3\",\n \"samplingRate\": 24000\n}", CURLOPT_HTTPHEADER => [ "Accept: audio/webm;codecs=opus", "Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "io" "net/http" "os" "strings" ) func main() { url := "https://users.rime.ai/v1/rime-tts" payload := strings.NewReader("{\n \"speaker\": \"cove\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv3\",\n \"samplingRate\": 24000\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "audio/webm;codecs=opus") req.Header.Add("Authorization", "Bearer YOUR_API_KEY") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) _ = os.WriteFile("output.webm", body, 0644) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/v1/rime-tts") .header("Accept", "audio/webm;codecs=opus") .header("Authorization", "Bearer YOUR_API_KEY") .header("Content-Type", "application/json") .body("{\n \"speaker\": \"cove\",\n \"text\": \"Hello from Rime!\",\n \"modelId\": \"mistv3\",\n \"samplingRate\": 24000\n}") .asBytes(); Files.write(Paths.get("output.webm"), response.getBody()); ``` # Websockets Source: https://docs.rime.ai/api-reference/mistv3/websockets GET wss://users-ws.rime.ai/ws Mist v3 plain-text WebSocket (/ws): send text, receive raw audio bytes. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This WebSocket accepts plain text and returns raw audio bytes in the format you set with `audioFormat`. You pass every synthesis parameter as a query parameter when you open the connection, and those settings apply for the life of the connection. The API buffers input until it detects a sentence boundary, typically at `.`, `?`, or `!`, so synthesis starts once it has enough text for natural prosody. The wait is most noticeable on the first sentence. After that, later text usually arrives while earlier audio is still playing, and the buffering becomes largely invisible. To change when synthesis starts, set `segment`. ## Messages ### Send Send bare text, not JSON. ```example theme={null} This will be converted to audio via websockets ``` ### Receive Your client receives raw audio bytes in the `audioFormat` set at connection time. Append the messages in order to rebuild the audio. ## Commands Send these strings as text messages to control the buffer. ### `` Discards buffered text that hasn't been synthesized yet. Send it when the user interrupts. It doesn't cancel a synthesis already in progress, so stop playback in your client and drop any audio that still arrives. ### `` Synthesizes whatever text is buffered, without waiting for a sentence boundary, and sends the audio. ### `` Synthesizes whatever text is buffered, sends the audio, and then the server closes the connection. ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). Set to `mistv3`. One of `wav`, `mp3` (or `mpeg`), `ogg` (Opus in OGG), `webm` (Opus in WebM), `pcm` (or `l16`), or `mulaw` (or `pcmu`). Unrecognized values fall back to `wav`. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds. Example: `Hi. <200> I'd love to have a conversation with you.` adds a 200ms pause. Learn more about [custom pauses](/docs/custom-pauses). The sampling rate in Hz. Default: 24000. Values above 24000 are upsampled. Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. Adjusts the speed of speech. Higher than 1.0 is faster and lower than 1.0 is slower. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis ```python Python theme={null} import asyncio import websockets class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws?speaker={speaker}&modelId=mistv3&audioFormat=mp3" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_tokens(self, websocket, message): for token in message: await websocket.send(token) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break self.audio_data += audio async def run(self, message): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_tokens(websocket, message), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) message = [ "This ", "is ", "a ", "sentence, ", "that ", "will ", "produce ", "audio.", "", ] client = RimeClient("cove", api_key="YOUR_API_KEY") asyncio.run(client.run(message)) client.save_audio("output.mp3") ``` # Websockets JSON Source: https://docs.rime.ai/api-reference/mistv3/websockets-json GET wss://users-ws.rime.ai/ws3 Mist v3 JSON WebSocket (/ws3): structured events with base64 audio chunks and word-level timestamps. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This WebSocket sends and receives JSON messages. Compared with the [plain-text WebSocket](/api-reference/mistv3/websockets), it adds word-level timestamps, a `done` event after each synthesis, and `contextId` tagging. You pass every synthesis parameter as a query parameter when you open the connection, and those settings apply for the life of the connection. The API buffers input until it detects a sentence boundary, typically at `.`, `?`, or `!`, so synthesis starts once it has enough text for natural prosody. The wait is most noticeable on the first sentence. After that, later text usually arrives while earlier audio is still playing, and the buffering becomes largely invisible. To change when synthesis starts, set `segment`. ## Messages ### Send #### Text Sends text for synthesis. This is the message your client sends most often. schema: ```typescript theme={null} type TextMessage = { text: string, contextId?: string, } ``` examples: ```json theme={null} { "text": "this is the minimum text message." } { "text": "this is a text message with a context id.", "contextId": "159495B1-5C81-4C73-A51A-9CE10A08239E" } ``` If you set `contextId`, the server attaches it to the events it sends back for that text. The server tracks one context ID at a time. #### Clear Discards buffered text that hasn't been synthesized yet. Send it when the user interrupts. It doesn't cancel a synthesis already in progress, so stop playback in your client and drop any audio that still arrives. ```json theme={null} { "operation": "clear" } ``` #### Flush Synthesizes whatever text is buffered, without waiting for a sentence boundary, and sends the audio. ```json theme={null} { "operation": "flush" } ``` #### EOS Synthesizes whatever text is buffered, sends the audio, and then the server closes the connection. ```json theme={null} { "operation" : "eos" } ``` ### Receive #### Chunk Carries a piece of the synthesized audio. This is the event your client receives most often. ```typescript theme={null} type Base64String = string type AudioChunkEvent = { type: "chunk", data: Base64String, contextId: string | null, } ``` `data` holds base64-encoded audio in the `audioFormat` set at connection time. Decode each chunk and append the bytes in order to rebuild the audio. If the text that produced this audio had a `contextId`, the event includes it. #### Timestamps The server sends word-level timestamps alongside the audio chunks, so your client can tell which words have been spoken at any point. When the user talks over the output, map the playback position back to the last word they actually heard. Timestamps are emitted only when `lang` is `en`/`eng` or `es`/`spa`, or when `lang` is omitted. Requests in any other language receive `chunk` and `done` events with no `timestamps` event and no error (this includes fr and de). Don't block playback while waiting for a timestamps event. ```typescript theme={null} type TimestampsEvent = { type: "timestamps", word_timestamps: { words: string[], start: number[], end: number[], }, contextId: string | null, } ``` The three arrays inside `word_timestamps` are the same length and index-aligned: for a given index `i`, `words[i]` is spoken from `start[i]` to `end[i]`. Times are in seconds, measured from the beginning of the audio for the current synthesis. If a context id was attached to the text that produced this audio, it is included on the event. Example payload: ```json theme={null} { "type": "timestamps", "word_timestamps": { "words": ["Testing", "mistv3", "timestamps."], "start": [0, 0.35396, 1.41584], "end": [0.35396, 1.41584, 3.18564] }, "contextId": null } ``` #### Done After the last audio chunk for a synthesis batch has been sent, the server emits a `done` event. This signals that the current synthesis is fully complete. If the client sends more text and triggers further synthesis, another `done` will follow. ```typescript theme={null} type DoneEvent = { type: "done", contextId: string | null, } ``` When exactly `done` fires depends on the `segment` setting. See [Segmentation and behavior settings](/docs/websockets-segment) for full details. #### Error If a message is malformed or unexpected, the server responds immediately with an `error` event. The server does *not* close the connection and keeps accepting well-formed messages, so your client decides whether to close it. ```typescript theme={null} type ErrorEvent = { type: "error", message: string, } ``` ## Variable parameters Must be a voice from the [Rime voice catalog](/docs/voices). Set to `mistv3`. One of `wav`, `mp3` (or `mpeg`), `ogg` (Opus in OGG), `webm` (Opus in WebM), `pcm` (or `l16`), or `mulaw` (or `pcmu`). Unrecognized values fall back to `wav`. If provided, the language must match the language spoken by the selected speaker. Verify the pairing in the [Rime voice catalog](/docs/voices). When set to true, adds pauses between words enclosed in angle brackets. The number inside the brackets specifies the pause duration in milliseconds. Example: `Hi. <200> I'd love to have a conversation with you.` adds a 200ms pause. Learn more about [custom pauses](/docs/custom-pauses). The sampling rate in Hz. Default: 24000. Values above 24000 are upsampled. Comma-separated list of speed values applied to words in square brackets. Values \< 1.0 speed up speech, > 1.0 slow it down. Example: "This is \[slow] and \[fast]", use "3, 0.5" to make "slow" slower and "fast" faster. Adjusts the speed of speech. Higher than 1.0 is faster and lower than 1.0 is slower. Controls how text is segmented for synthesis. Available options: * "immediate" - Synthesizes text immediately without waiting for complete sentences * "never" - Never segments the text, waits for explicit flush or EOS * "bySentence" (default) - Waits for complete sentences before synthesis ```python Python theme={null} import asyncio import json import websockets import base64 class RimeClient: def __init__(self, speaker, api_key): self.url = f"wss://users-ws.rime.ai/ws3?speaker={speaker}&modelId=mistv3&audioFormat=mp3" self.auth_headers = { "Authorization": f"Bearer {api_key}" } self.audio_data = b'' async def send_messages(self, websocket, messages): for message in messages: await websocket.send(json.dumps(message)) async def handle_audio(self, websocket): while True: try: audio = await websocket.recv() except websockets.exceptions.ConnectionClosedOK: break message = json.loads(audio) if message['type'] == 'chunk': self.audio_data += base64.b64decode(message['data']) if message['type'] == 'timestamps': print("Rime model pronounced the words...\n") for w, t in zip(message['word_timestamps']['words'], message['word_timestamps']['start']): print(f"'{w}' at time {t}") async def run(self, messages): async with websockets.connect(self.url, additional_headers=self.auth_headers) as websocket: await asyncio.gather( self.send_messages(websocket, messages), self.handle_audio(websocket), ) def save_audio(self, file_path): with open(file_path, 'wb') as f: f.write(self.audio_data) print(f"\n Audio saved at {file_path}") message = [ {"text": "This "}, {"text": "is "}, {"text": "an "}, {"text": "incomplete "}, {"text": "sentence "}, {"operation": "eos"}, ] client = RimeClient("cove", api_key="YOUR_API_KEY") asyncio.run(client.run(message)) client.save_audio("output.mp3") ``` # Coverage Source: https://docs.rime.ai/api-reference/other/oov POST https://users.rime.ai/oov Coverage endpoint: check which input words are not yet in Rime's pronunciation dictionary. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This endpoint returns the words in your input that are absent from Rime's pronunciation dictionary. The API still synthesizes uncovered words using the model's predicted pronunciation, so listen to brand names, technical terms, and names before production use. Dictionary additions typically take about a week. Contact your account manager through Slack or email, or write to [sales@rime.ai](mailto:sales@rime.ai), if you need a different turnaround or have an SLA. For immediate Mist-family control (v1, v2, or English v3), [generate a custom pronunciation](/docs/custom-pronunciation) by hand or from a recording with the [Phonemize API](/api-reference/other/phonemize). ## Example Send the words to check as `text`: ```bash theme={null} curl -X POST https://users.rime.ai/oov \ -H 'Authorization: Bearer ' \ -d '{"text": "This is just a testt. This, is, also, a, testtt"}'; ``` The response is an array of the words that aren't in the current Rime dictionary. An empty array means every word is covered: ```bash theme={null} ["testt","testtt"] ``` ## Variable parameters One or more words to check against Rime's pronunciation dictionary. Separate words with spaces, commas, or newlines. ```bash cURL theme={null} curl --request POST \ --url https://users.rime.ai/oov \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --fail \ --data '{ "text": "" }' ``` ```python Python theme={null} import requests url = "https://users.rime.ai/oov" payload = { "text": "" } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"text":""}' }; fetch('https://users.rime.ai/oov', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://users.rime.ai/oov", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"text\": \"\"\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://users.rime.ai/oov" payload := strings.NewReader("{\n \"text\": \"\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://users.rime.ai/oov") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"text\": \"\"\n}") .asString(); ``` ```json 200: words not in dictionary theme={null} ["testt", "testtt"] ``` ```json 200: all words covered theme={null} [] ``` # Phonemize Source: https://docs.rime.ai/api-reference/other/phonemize POST https://optimize.rime.ai/phonemize Phonemize endpoint: convert a recording of a word into a phonetic string in the Rime phonetic alphabet. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This endpoint converts a short audio recording of a word into a phonetic string in the [Rime phonetic alphabet](/platform/rime-phonetic-alphabet). Use it when you know how a word should sound but don't want to write the phonetic string by hand: record the word (or synthesize it), post the audio, and paste the returned string into a TTS request inside curly brackets with `phonemizeBetweenBrackets: true`. See [Custom pronunciation](/docs/custom-pronunciation). Custom pronunciation strings are supported on **Mist v1, Mist v2, and English Mist v3**. Coda and non-English Mist v3 accept `phonemizeBetweenBrackets` and ignore it. For an overview of all the ways to control pronunciation, see [Pronunciation control](/platform/pronunciation-control). ## Request Unlike Rime's other endpoints, the request body is the **raw audio bytes**, not JSON or multipart form data. Set the `Content-Type` header to match the audio format. WAV (`audio/wav`) and MP3 (`audio/mpeg`) are supported. ## Example Generate or record audio of the word, for example with the [Rime CLI](/cli-reference/overview): ```bash theme={null} rime tts -m coda -l en -s astra "hello" -o speech.wav ``` Post the file as the raw request body. `--data-binary` sends the bytes unchanged, while `-d` would strip newlines and corrupt the audio: ```bash theme={null} curl -X POST https://optimize.rime.ai/phonemize \ -H "Authorization: Bearer $(rime key)" \ -H "Content-Type: audio/wav" \ --data-binary @speech.wav ``` The response includes the phonetic string: ```json theme={null} { "audioId": "9b2d8ad2-0618-4e96-b255-98b2f7488061", "phonemeString": "h0El1o !", "authed": 1 } ``` ## Response fields * `audioId`: identifier of the uploaded audio clip. * `phonemeString`: the phonetic transcription in the [Rime phonetic alphabet](/platform/rime-phonetic-alphabet). The string may end with a punctuation token (for example, `!` or `?`). Strip that token before you use the string inside `{}`. * `authed`: always `1`. ```bash cURL theme={null} curl --request POST \ --url https://optimize.rime.ai/phonemize \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: audio/wav' \ --fail \ --data-binary @speech.wav ``` ```python Python theme={null} import requests url = "https://optimize.rime.ai/phonemize" headers = { "Authorization": "Bearer ", "Content-Type": "audio/wav" } with open("speech.wav", "rb") as f: response = requests.request("POST", url, data=f, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} import { readFile } from 'node:fs/promises'; const audio = await readFile('speech.wav'); const options = { method: 'POST', headers: { Authorization: 'Bearer ', 'Content-Type': 'audio/wav' }, body: audio }; fetch('https://optimize.rime.ai/phonemize', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```json 200 theme={null} { "audioId": "9b2d8ad2-0618-4e96-b255-98b2f7488061", "phonemeString": "h0El1o !", "authed": 1 } ``` # Text Normalization Source: https://docs.rime.ai/api-reference/other/textnorm POST https://optimize.rime.ai/textnorm Return the grammar normalizer's output for an input string. The Rime API authenticates every request with a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. See [API authentication](/docs/api-authentication) for how to create a key. ## Overview This endpoint returns the grammar normalizer's output for an input string. Use it to preview how numbers, phone numbers, dates, and other non-standard words will be spoken, or to debug an unexpected pronunciation. The output matches Coda's normalization. Mist v3 can group `spell()` sequences differently. Defaults to English. Pass the `lang` field for other languages. The full list is in [Languages](/docs/voices#languages). For details on what's normalized natively, known gaps, and how to pre-normalize problematic patterns, see [Text normalization](/docs/text-normalization). ## Example Send the string as `text`, and optionally a `lang` code: ```bash theme={null} curl -X POST https://optimize.rime.ai/textnorm \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text":"1234 1,2,3,4 1-800-444-4141 "}' ``` The response includes the normalized string: ```json theme={null} {"normalized":"one two three four, one, two, three, four, one, eight hundred, four four four, four one four one"} ``` Check each non-standard word in the output. Here `1234` is read digit by digit, and the phone number keeps its grouping, with `800` read as "eight hundred". If a reading is wrong for your context, pre-normalize that text before you send it. [Text normalization](/docs/text-normalization) explains how. To normalize text in a non-English language, pass a language code: ```bash theme={null} curl -X POST https://optimize.rime.ai/textnorm \ -H "Authorization: Bearer $(rime key)" \ -H "Content-Type: application/json" \ -d '{"text":"Tengo 2 perros","lang":"es"}' ``` ## Variable parameters The string you'd like to normalize. Numbers, phone numbers, and other non-standard words will be expanded into their spoken form. Language code (for example, `en`, `es`, `fr`, `de`, and [additional languages](/docs/voices#languages)) selecting the normalization rules. Defaults to English when omitted. ```bash cURL theme={null} curl --request POST \ --url https://optimize.rime.ai/textnorm \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --fail \ --data '{ "text": "" }' ``` ```python Python theme={null} import requests url = "https://optimize.rime.ai/textnorm" payload = { "text": "" } headers = { "Accept": "application/json", "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.request("POST", url, json=payload, headers=headers) print(response.text) ``` ```javascript JavaScript theme={null} const options = { method: 'POST', headers: { Accept: 'application/json', Authorization: 'Bearer ', 'Content-Type': 'application/json' }, body: '{"text":""}' }; fetch('https://optimize.rime.ai/textnorm', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); ``` ```php PHP theme={null} "https://optimize.rime.ai/textnorm", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{\n \"text\": \"\"\n}", CURLOPT_HTTPHEADER => [ "Accept: application/json", "Authorization: Bearer ", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { echo $response; } ``` ```go Go theme={null} package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "https://optimize.rime.ai/textnorm" payload := strings.NewReader("{\n \"text\": \"\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```java Java theme={null} HttpResponse response = Unirest.post("https://optimize.rime.ai/textnorm") .header("Accept", "application/json") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"text\": \"\"\n}") .asString(); ``` ```json 200 theme={null} { "normalized": "one two three four, one, two, three, four, one, eight hundred, four four four, four one four one" } ``` # Overview Source: https://docs.rime.ai/cli-reference/overview Install and get started with the Rime CLI: a command-line tool for synthesizing and listening to AI speech. The Rime CLI synthesizes AI speech from your terminal. It streams audio during generation, plays it live with a waveform visualization, and saves WAV or MP3 files. ## Installation ```bash Shell script theme={null} curl -fsSL https://rime.ai/install-cli.sh | sh ``` ```bash Homebrew theme={null} brew tap rimelabs/rime-cli && brew install rime-cli ``` After installing, run `rime login` to save your API key, then `rime hello`. If you hear the greeting, your key, the API, and playback all work. ## Commands Synthesize text to speech and play or save audio Generate curl commands for direct API requests Manage configuration and named environments Authenticate with the Rime dashboard rime play, rime hello, rime speedtest, rime usage, and more Global flags, environment variables, and configuration format Fix common errors and installation issues # Reference Source: https://docs.rime.ai/cli-reference/reference Global flags, environment variables, configuration file format, audio formats, and metadata embedding for the Rime CLI. ## Global flags (all commands) | Flag | Short | Default | Description | | - | - | - | - | | `--quiet` | `-q` | `false` | Suppress non-essential output | | `--json` | -- | `false` | Output results as JSON | | `--env` | `-e` | -- | Named environment to use from config | | `--config` | `-c` | -- | Path to a custom config file | | `--version` | `-v` | -- | Print version information | | `--help` | `-h` | -- | Help for any command | ## Environment variables | Variable | Description | | - | - | | `RIME_CLI_API_KEY` | API key for authentication (overrides the key in `rime.toml`) | | `RIME_API_URL` | API endpoint URL (overrides the URL in `rime.toml`) | | `RIME_AUTH_HEADER_PREFIX` | Authorization header prefix (default: `Bearer`) | | `RIME_DASHBOARD_URL` | Dashboard URL for `rime login` (default: `https://app.rime.ai`) | | `RIME_OPTIMIZE_URL` | Usage API endpoint for `rime usage` (default: `https://optimize.rime.ai`) | | `RIME_INSTALL` | Install directory used by the shell installer (default: `~/.rime`) | ## Configuration The CLI uses a TOML config file at `~/.rime/rime.toml`. You can define multiple named environments for different API endpoints. ```toml theme={null} api_key = "your_api_key" api_url = "https://users.rime.ai/v1/rime-tts" [env.staging] api_url = "https://staging.rime.ai/v1/rime-tts" [env.onprem] api_url = "https://rime.internal:8080/v1/rime-tts" api_key = "different_key" auth_header_prefix = "Api-Key" ``` Select an environment with the `--env` flag. This request goes to the `staging` URL and uses the top-level `api_key`, because `staging` doesn't set its own: ```bash theme={null} rime tts "Hello" -s astra -m coda --env staging ``` **Resolution order:** Environment variables override config file values, which override defaults. Within the config file, named environment values override top-level values. A command's `--api-url` flag overrides the URL from all of these. ## Audio formats | Format | Extension | Default for | Notes | | - | - | - | - | | WAV | `.wav` | `coda`, `mistv3` | Uncompressed, higher quality, larger files | | MP3 | `.mp3` | `mistv2`, `mist` | Compressed, smaller files | ## Metadata embedding Audio files saved by the CLI include embedded metadata (voice, model, text). This metadata is visible in `rime play` waveform output and in media players like Finder or Preview. * **WAV files:** LIST/INFO chunk (`IART`, `INAM`, `ICMT`) * **MP3 files:** ID3v2.3 tags (`TPE1`, `TIT2`, `COMM`) # Authentication Source: https://docs.rime.ai/cli-reference/rime-auth Authenticate the Rime CLI using rime login, rime logout, and rime key. ## `rime login` Opens your browser to the Rime dashboard for OAuth-based authentication, then saves your API key to `~/.rime/rime.toml`. The CLI starts a local callback server to receive the key from the dashboard. ```bash theme={null} rime login ``` Demo of the rime login command No flags. The CLI checks the key before saving it and doesn't save a key the API rejects as invalid. If the check fails for another reason, such as a network error, the CLI saves the key anyway and prints a warning, so run `rime hello` to confirm it works. *** ## `rime logout` Remove your saved API key by deleting the config file at `~/.rime/rime.toml`. Deleting the file also removes any named environments you added, so run `rime config init` or `rime login` to set up again. ```bash theme={null} rime logout ``` No flags. *** ## `rime key` Print the resolved API key (no trailing newline). Useful in shell scripts and as a subexpression. For example, `rime curl` uses `$(rime key)` in its generated commands. ```bash theme={null} rime key ``` No flags. Resolves the key from config or `RIME_CLI_API_KEY`, using the active environment. If no key resolves, it prints nothing, and a command that uses `$(rime key)` sends an empty key. Run `rime config show` to see where the key comes from. # rime config Source: https://docs.rime.ai/cli-reference/rime-config Manage Rime CLI configuration and named environments with rime config subcommands. The `rime config` subcommands manage `~/.rime/rime.toml`, the TOML file that holds your API key and named environments. ## `rime config init` Create a new config file. In a terminal, the command prompts for an API key. You can press Enter to skip it and add the key later. ```bash theme={null} rime config init ``` | Flag | Default | Description | | - | - | - | | `--force` | `false` | Overwrite an existing config file | The generated file names both standard Rime endpoints as environments and makes `users` the default: ```toml theme={null} api_key = "your_api_key_here" default_env = "users" [env.users] api_url = "https://users.rime.ai/v1/rime-tts" [env.users-east] api_url = "https://users-east.rime.ai/v1/rime-tts" ``` Both environments inherit the single top-level `api_key`. To find out which endpoint responds faster from your network, run [`rime speedtest`](/cli-reference/rime-monitoring). It also offers to switch `default_env` to the faster one. Older config files without `default_env` continue to work: the top-level `api_url` and `api_key` fields are still respected as the fallback default. ## `rime config list` List all configured environments. The currently active default environment is marked with a `*` in the `NAME` column. ```bash theme={null} rime config list ``` ``` NAME URL AUTH -------------------------------------------------------------------------------- users * https://users.rime.ai/v1/rime-tts Bearer users-east https://users-east.rime.ai/v1/rime-tts Bearer ``` | Flag | Default | Description | | - | - | - | | `--json` | `false` | Output as JSON | ## `rime config default` Get or set the default environment. ```bash theme={null} # Print the current default environment name rime config default # Switch the default to a different environment rime config default users-east ``` With no arguments, prints the name of the current default environment: ``` users ``` With a name argument, updates `default_env` in `~/.rime/rime.toml` and confirms: ``` Default environment set to "users-east" ``` No flags. ## `rime config show` Show the fully resolved configuration for a given environment, including where the API key comes from (config file vs. environment variable). ```bash theme={null} rime config show ``` | Flag | Short | Default | Description | | - | - | - | - | | `--env` | `-e` | `default` | Environment to show | | `--json` | -- | `false` | Output as JSON | | `--show-key` | -- | `false` | Display the full API key (redacted by default) | **Example output:** ``` Environment: users API URL: https://users.rime.ai/v1/rime-tts API Key: rime_aHR0cHM6Ly... (redacted) Auth Prefix: Bearer Auth Header: Authorization: Bearer (redacted) ``` ## `rime config add` Add a named environment to `~/.rime/rime.toml`. Prompts interactively for API URL, API key (input hidden), and an optional auth prefix. You cannot add an environment named `default`. Use `rime config default` to change which environment is the default. ```bash theme={null} rime config add ``` | Flag | Description | | - | - | | `--url` | API URL (default: `https://users.rime.ai/v1/rime-tts`) | | `--key` | API key (skips interactive prompt) | | `--auth-prefix` | Auth header prefix, e.g. `Bearer` (optional) | **Examples:** ```bash theme={null} # Add a staging environment interactively rime config add staging # Add an on-prem environment non-interactively rime config add onprem --url https://rime.internal:8080/v1/rime-tts --key your_key_here ``` ## `rime config rm` Remove a named environment from `~/.rime/rime.toml`. Prompts for confirmation unless `--yes` is passed. ```bash theme={null} rime config rm ``` | Flag | Short | Default | Description | | - | - | - | - | | `--yes` | `-y` | `false` | Skip confirmation prompt | ## `rime config edit` Open `~/.rime/rime.toml` in your default editor (`$VISUAL` or `$EDITOR`, falling back to `nano` or `vi`). ```bash theme={null} rime config edit ``` No flags. Requires the config file to exist. Run `rime config init` first if needed. # rime curl Source: https://docs.rime.ai/cli-reference/rime-curl Generate a ready-to-run curl command for the Rime TTS API. Generate a curl command for making TTS API requests. The generated command uses `$(rime key)` as a shell expression, so your API key never appears in the printed command. Instead, the shell resolves it when you run the command. ```bash theme={null} rime curl [TEXT] ``` If you provide text, `--speaker` and `--model-id` are required. With no arguments, the command prints an example request. The generated command saves audio to `output.wav`, or `output.mp3` for `mist` and `mistv2`. It includes `--fail`, so an HTTP error stops curl instead of being written to the output file. ## Optional flags | Flag | Short | Default | Description | | - | - | - | - | | `--speaker` | `-s` | `astra`\* | Voice speaker to use | | `--model-id` | `-m` | `coda`\* | Model ID | | `--lang` | `-l` | -- | BCP 47 language tag. Defaults to the model's own language | | `--speed-alpha` | -- | `1` | Speed multiplier, which must be greater than 0. For `mist`/`mistv2`: lower is faster. For `coda` and `mistv3`: higher is faster | | `--sampling-rate` | -- | -- | Output sampling rate in Hz. Coda: `8000`, `16000`, `22050`, `24000`, `44100`, `48000`, `96000`. Mist: `4000`–`44100` | | `--oneline` | -- | `false` | Output as a single line for easy copy-paste | | `--api-url` | -- | -- | API URL override | \*Defaults apply only when run without arguments. When text is provided, `--speaker` and `--model-id` are required. ## Coda flags The CLI rejects these flags for `mist`, `mistv2`, and `mistv3`. | Flag | Default | Description | | - | - | - | | `--max-tokens` | `1200` | Max output tokens (200–5000) | | `--temperature` | `0.5` | Sampling temperature (0–1) | | `--top-p` | `1` | Nucleus sampling threshold (0–1) | | `--repetition-penalty` | `1.5` | Repetition penalty (1–2) | ## mist/mistv2/mistv3 flags The CLI rejects these flags for `coda`. | Flag | Description | | - | - | | `--inline-time-scale-factor` | Comma-separated per-segment speed values | | `--pause-between-brackets` | Insert pause at bracketed markers | | `--phonemize-between-brackets` | Phonemize text in brackets. On `mistv3`, English only (see [Custom pronunciation](/docs/custom-pronunciation)) | ## mist/mistv2 flags Only `mist` and `mistv2` support these flags, so the CLI rejects them for `mistv3`. | Flag | Description | | - | - | | `--no-text-normalization` | Disable text normalization | | `--save-oovs` | Save out-of-vocabulary words | ## Examples ```bash theme={null} # Show example curl command rime curl # Generate curl for custom text rime curl "Hello from Rime" -s celeste -m coda # Single-line output rime curl "Hello" -s astra -m coda --oneline ``` # rime hello & rime play Source: https://docs.rime.ai/cli-reference/rime-hello-play Quick audio demo and terminal waveform playback with the Rime CLI. ## `rime hello` Generates a time-appropriate greeting ("good morning/afternoon/evening, this is Vespera speaking") using the Vespera voice on Coda. The text and voice are fixed, so if you hear the greeting, your API key, the API, and audio playback all work. ```bash theme={null} rime hello ``` Demo of the rime hello command ### Optional flags | Flag | Short | Default | Description | | - | - | - | - | | `--output` | `-o` | -- | Output file path (plays audio by default) | | `--api-url` | -- | -- | API URL override | ### Examples ```bash theme={null} # Play the greeting rime hello # Save the greeting to a file rime hello -o greeting.wav # Output as JSON rime hello --json ``` *** ## `rime play` Play a WAV audio file with terminal waveform visualization. Headless builds have no audio support, so `rime play` exits with an error there. Instead, save audio with `rime tts -o FILE` and play it elsewhere. ```bash theme={null} rime play FILE ``` Demo of the rime play command ### Examples ```bash theme={null} rime play output.wav ``` # Monitoring and usage Source: https://docs.rime.ai/cli-reference/rime-monitoring Measure latency, view character usage, and uninstall the Rime CLI. ## `rime speedtest` Measure time-to-first-byte (TTFB) for configured environments. The command sends a TTS request to each endpoint and reports the latency, so you can pick the fastest endpoint from your network as your default. Each test request is a real synthesis request made with your API key. ```bash theme={null} rime speedtest ``` ### Flags | Flag | Short | Default | Description | | - | - | - | - | | `--model` | `-m` | `coda` | Model ID for the test request | | `--speaker` | `-s` | `astra` | Speaker for the test request | | `--lang` | `-l` | -- | BCP 47 language tag for the test request. Defaults to the model's own language | | `--text` | -- | `running speedtest.` | Text to synthesize | | `--runs` | -- | `1` | Number of requests per endpoint. When greater than 1, reports mean/min/max | | `--timeout` | -- | `10s` | Per-request timeout (`0` disables timeout) | | `--url` | -- | -- | Additional URL to test (repeatable). Forwards your configured API credentials to that URL | | `--env` | -- | -- | Only test these named environments from config (repeatable) | | `--yes` | `-y` | `false` | Automatically switch the default environment if a faster one is found | `--url` forwards your configured API credentials to every supplied URL. Use it only with endpoints you trust. The CLI also prints this warning at runtime. ### Behavior * No flags: tests all configured environments * `--url` alone: tests only the specified URLs and skips the config environments * `--env` + `--url`: tests both the named envs and the extra URLs * After the test completes, if the fastest environment differs from the current default, the CLI prompts you to switch. Use `--yes` to skip the prompt and switch automatically. ### Example output (single run) ``` ENV URL TTFB -------------------------------------------------------------------------------- users https://users.rime.ai/v1/rime-tts 245.12ms users-east https://users-east.rime.ai/v1/rime-tts 189.40ms Fastest: users-east (189.40ms) Switch default to "users-east"? [y/N]: ``` ### Example output (`--runs 3`) ``` ENV URL TTFB (3 runs) -------------------------------------------------------------------------------- users https://users.rime.ai/v1/rime-tts mean=245.12ms min=221.30ms max=271.50ms users-east https://users-east.rime.ai/v1/rime-tts mean=189.40ms min=175.10ms max=203.80ms Fastest: users-east (189.40ms) Switch default to "users-east"? [y/N]: ``` A single run can catch one slow request, so use `--runs 3` or more before switching your default on a small difference. When `--runs` is greater than 1, the JSON output includes `ttfb_min_ms` and `ttfb_max_ms` fields in addition to `ttfb_ms` (mean). *** ## `rime usage` Display daily character usage per model, Coda included. The table has one column for each model with usage in the window plus a Total column. Cloud and on-prem usage are summed per day, and a footer shows the split when both appear. Days are UTC. Per-model history begins 2026-04-01, so earlier days show 0. ```bash theme={null} rime usage ``` ### Flags | Flag | Default | Description | | - | - | - | | `--days` | `7` | Days of history to show, ending today (1 to 90) | | `--from` | | Start date as `YYYY-MM-DD`, inclusive. On its own, the range runs through today | | `--to` | | End date as `YYYY-MM-DD`, inclusive. On its own, the range is `--days` ending on this date | | `--env` | | Count only one environment: `cloud` or `onprem` | | `--csv` | `false` | Output one row per day, environment, and model | A range cannot exceed 90 days. The global `--json` flag prints the per-day records unchanged: each day carries a `breakdown` list of `{model, environment, charCount}` entries, and a day with no usage has an empty list. ### Example output ``` Day mistv3 coda Total ---------- ------- ------- ------- 2026-05-18 12,400 31,250 43,650 2026-05-19 0 28,900 28,900 Cloud 70,100 On-prem 2,450 (use --env to filter) ``` The same two days as CSV: ``` day,environment,model,chars 2026-05-18,cloud,mistv3,12400 2026-05-18,cloud,coda,30000 2026-05-18,onprem,coda,1250 2026-05-19,cloud,coda,27700 2026-05-19,onprem,coda,1200 ``` *** ## `rime uninstall` Remove the Rime CLI binary, configuration, and shell PATH entries. For a shell-script install, the command lists what it will remove and asks for confirmation before deleting anything. ```bash theme={null} rime uninstall ``` ### Flags | Flag | Short | Default | Description | | - | - | - | - | | `--yes` | `-y` | `false` | Skip the confirmation prompt | If you installed via Homebrew, the command removes nothing and prints `brew uninstall rime-cli` for you to run instead. # rime tts Source: https://docs.rime.ai/cli-reference/rime-tts Synthesize text to speech from the command line using the Rime CLI. Synthesize text to speech in WAV or MP3. The CLI picks the format from the model: `mist` and `mistv2` default to MP3, while `coda` and `mistv3` default to WAV. Use `--format` to override. ```bash theme={null} rime tts TEXT --speaker VOICE --model-id MODEL ``` Demo of the rime tts command ## Required flags | Flag | Short | Description | | - | - | - | | `--speaker` | `-s` | Voice speaker to use (e.g., `astra`, `celeste`, `orion`) | | `--model-id` | `-m` | Model ID: `coda`, `mistv3`, `mistv2`, or `mist` | ## Optional flags | Flag | Short | Default | Description | | - | - | - | - | | `--output` | `-o` | -- | Output file path. Use `-` for stdout. If omitted, plays audio directly | | `--play` | `-p` | `false` | Play audio after synthesis (default behavior when no output is specified) | | `--lang` | `-l` | -- | BCP 47 language tag (e.g., `en`, `es`, `fr`). Defaults to the model's own language | | `--format` | `-f` | -- | Audio format: `wav` or `mp3` (overrides model default) | | `--speed-alpha` | -- | `1` | Speed multiplier, which must be greater than 0. For `mist`/`mistv2`: lower is faster. For `coda` and `mistv3`: higher is faster | | `--sampling-rate` | -- | -- | Output sampling rate in Hz. Coda: `8000`, `16000`, `22050`, `24000`, `44100`, `48000`, `96000`. Mist: `4000`–`44100` | | `--api-url` | -- | -- | API URL (default: `$RIME_API_URL` or `https://users.rime.ai/v1/rime-tts`) | ## Coda flags The CLI rejects these flags for `mist`, `mistv2`, and `mistv3`. | Flag | Default | Description | | - | - | - | | `--max-tokens` | `1200` | Max output tokens (200–5000) | | `--temperature` | `0.5` | Sampling temperature (0–1) | | `--top-p` | `1` | Nucleus sampling threshold (0–1) | | `--repetition-penalty` | `1.5` | Repetition penalty (1–2) | ## mist/mistv2/mistv3 flags The CLI rejects these flags for `coda`. | Flag | Description | | - | - | | `--inline-time-scale-factor` | Comma-separated per-segment speed values | | `--pause-between-brackets` | Insert pause at bracketed markers | | `--phonemize-between-brackets` | Phonemize text in brackets. On `mistv3`, English only (see [Custom pronunciation](/docs/custom-pronunciation)) | ## mist/mistv2 flags Only `mist` and `mistv2` support these flags, so the CLI rejects them for `mistv3`. | Flag | Description | | - | - | | `--no-text-normalization` | Disable text normalization | | `--save-oovs` | Save out-of-vocabulary words | ## Examples ```bash theme={null} # Play audio directly through speakers rime tts "Hello world" -s astra -m coda # Save to a WAV file rime tts "Hello world" -s astra -m coda -o output.wav # Pipe audio to stdout rime tts "Hello world" -s astra -m coda -o - > audio.wav # Use mistv3 (WAV by default) rime tts "Hello world" -s peak -m mistv3 # Use mistv2 (outputs MP3 by default) rime tts "Hello world" -s peak -m mistv2 # Synthesize in Spanish with a Spanish Coda voice rime tts "Hola mundo" -s brisa -m coda -l es # JSON output with timing metadata rime tts "Hello world" -s astra -m coda -o output.wav --json ``` ## Language Omit `--lang` and the model synthesizes in its own language, which is what you want for a voice that speaks one language. Pass a BCP 47 tag to be explicit, and choose a voice that speaks that language: `astra` is an English voice, so the Spanish example above uses `brisa`. The CLI does not check `--lang`: it sends the value as given, and the API rejects a tag the model cannot serve. See [Languages](/docs/voices#languages) for what each model supports. # Troubleshooting Source: https://docs.rime.ai/cli-reference/troubleshooting Fix common issues with the Rime CLI. ## "no API key configured" `rime usage` reports this when no key is stored, but the TTS commands fail with "authentication failed: invalid API key" instead. Run `rime login` or set the environment variable: ```bash theme={null} export RIME_CLI_API_KEY=your_key_here ``` ## "authentication failed: invalid API key" The API rejected the key the CLI sent. Run `rime config show` to see which key the CLI resolved and where it came from, because a stale `RIME_CLI_API_KEY` overrides the key in `rime.toml`. Then verify the key at [app.rime.ai/tokens](https://app.rime.ai/tokens) and run `rime login` again. ## "unsupported format: ... (supported: wav, mp3)" The CLI writes only WAV or MP3. `mist` and `mistv2` default to MP3, and the other models default to WAV. If you pick a format a model can't serve, the API rejects it, not the CLI. Select a supported format explicitly: ```bash theme={null} rime tts "Hello" -s cove -m mistv2 -f mp3 ``` ## No audio playback * Check your system audio output settings * Try saving to a file instead: `rime tts "Hello" -s astra -m coda -o output.wav` * Headless builds (e.g., Docker) require `-o FILE` because they have no audio playback ## "command not found: rime" The shell installer adds its `bin` directory (`~/.rime/bin` by default) to your PATH through your shell's startup file, and the change reaches only new shells. Open a new terminal window or run: ```bash theme={null} source ~/.zshrc # or ~/.bashrc ``` If you skipped the installer's PATH prompt, the startup file wasn't changed. Add the line the installer printed to your shell config, then reload it. # Abbreviations, acronyms, and initialisms Source: https://docs.rime.ai/docs/abbreviations How Rime pronounces abbreviations, acronyms, and initialisms, with controls for exceptions. Rime pronounces most common abbreviations, acronyms, and initialisms correctly out of the box. The patterns below show how to format input when you want to control pronunciation explicitly. For a tour of text normalization across all categories, see [Text normalization](/docs/text-normalization). For specific patterns Rime doesn't expand cleanly, see [Pre-normalizing text](/docs/pre-normalization). ## Abbreviations | Format | Example | Reads as | | :- | :- | :- | | Title abbreviation | `Dr. Smith` | doctor smith | | Latin abbreviation | `e.g.` | for example | | Street abbreviation | `rd.` | road | | Saint abbreviation | `St. John` | saint john | Some abbreviations resolve from context. For example, `St.` reads as "saint" in `St. John` but "street" in `Main St.` See [Addresses](/docs/addresses) for street and state abbreviations in address context. ## Acronyms and initialisms Acronyms are pronounced as a single word. For example, `NASA` reads as "Nasa". Initialisms are pronounced as a series of letters, so `DNA` reads as "D N A". By default, Rime pronounces a series of capital letters as an acronym. Common initialisms such as `DNA`, `ID`, `USA`, `FBI`, and `CIA` are pronounced as a series of letters automatically. To force initialism pronunciation reliably, **use lowercase letters with a period and space after each**: | Format | Example | Reads as | | :- | :- | :- | | Capitalized acronym | `NASA` | Nasa | | Capitalized initialism (recognized) | `DNA` | D N A | | Lowercase + dotted | `d. n. a.` | D N A | | Lowercase + dotted | `u. p. s.` | U P S | | Lowercase + dotted | `g. p. a.` | G P A | You can also specify a custom pronunciation for any acronym or initialism using Rime's [custom pronunciations](/docs/custom-pronunciation) feature. ## Known gaps Context-dependent abbreviations like `Dr.`, `Mr.`, and `St.` rely on surrounding words to resolve and may not always read the way you expect. For workarounds and a drop-in prompt template, see [Pre-normalizing text](/docs/pre-normalization). ## Related * [Custom pronunciation](/docs/custom-pronunciation) for defining how a specific term should sound * [Spell function](/docs/spell) for forced letter-by-letter reading of unrecognized acronyms (`spell(NPI)`) * [Addresses, URLs, and emails](/docs/addresses) for street and state abbreviations in address context # Addresses, URLs, and emails Source: https://docs.rime.ai/docs/addresses How Rime automatically expands street addresses, URLs, and email addresses into spoken form. Rime expands addresses, URLs, and email addresses into their spoken form automatically. For a tour of text normalization across all categories, see [Text normalization](/docs/text-normalization). For specific patterns Rime doesn't expand cleanly, see [Pre-normalizing text](/docs/pre-normalization). ## Addresses Write out the full state name (for example, "Massachusetts" instead of "MA") for the most consistent results. Rime usually reads state abbreviations correctly in an address, and it expands common street abbreviations such as `Rd.` and `St.` into full words. All three inputs below produce the same reading. | Format | Example | Reads as | | :- | :- | :- | | Full street + state name | `529 Main Street, Boston, Massachusetts 02129` | five hundred twenty-nine main street, boston, massachusetts, zero two one two nine | | Abbreviated street + abbreviated state | `529 Main St., Boston, MA 02129` | five hundred twenty-nine main street, boston, massachusetts, zero two one two nine | | Mixed | `529 Main St, Boston, MA 02129` | five hundred twenty-nine main street, boston, massachusetts, zero two one two nine | ## URLs Schemes, `www.` prefixes, paths, and hyphens in domains are handled. Two-letter TLDs (`.io`, `.ai`, `.co`) are read letter-by-letter, while word-like TLDs (`.com`, `.org`, `.net`, `.info`, `.dev`) are read as words. | Format | Example | Reads as | | :- | :- | :- | | Bare `www.` URL | `www.example.com` | double-u double-u double-u dot example dot com | | HTTPS URL | `https://app.rime.ai` | h t t p s colon slash slash app dot rime dot a i | | URL with path | `www.shop.com/archive` | www dot shop dot com slash archive | | URL with path and scheme | `https://worldprime.io/about` | h t t p s colon slash slash world prime dot i o slash about | ## Emails | Format | Example | Reads as | | :- | :- | :- | | Standard email | `name@example.com` | name at example dot com | | Email with digits | `cloud799@icloud.com` | cloud seven nine nine at i cloud dot com | Rime's custom segmentation model handles email addresses. It breaks up compound words and handles punctuation and most top-level domains. If you hear something off, contact [Rime support](mailto:support@rime.ai). ## Known gaps Internationalized domain names (non-ASCII characters in URLs) aren't supported. For the full list of normalization gaps and how to handle them, see [Pre-normalizing text](/docs/pre-normalization). ## Related * [Numbers, currency, and measurements](/docs/numbers) for phone numbers and other numeric formats * [Spell function](/docs/spell) for forced letter-by-letter reading of unusual email addresses or vanity URLs # API authentication Source: https://docs.rime.ai/docs/api-authentication How to authenticate with the Rime TTS API using a bearer token. Every request to the Rime API requires a **bearer token**. Send it in the `Authorization` header. WebSocket clients that cannot set headers may instead pass `?rime_apikey=YOUR_API_KEY` on the connection URL, but this puts the key in URLs and proxy logs, so prefer a server-side bridge that sets the header. ## Get an API key An API key can synthesize speech against your account. Keep it on the server and treat it like a password. 1. Sign in to the [Rime dashboard](https://app.rime.ai). 2. In the Rime dashboard, open [**API Tokens**](https://app.rime.ai/tokens). 3. Create a token and copy its value. ## Use the token This request authenticates with a bearer token and saves the MP3 response to `hello.mp3`: ```bash theme={null} curl --request POST \ --url https://users.rime.ai/v1/rime-tts \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --header 'Accept: audio/mpeg' \ --fail \ --show-error \ --output hello.mp3 \ --data '{"speaker":"astra","text":"hello","modelId":"coda","lang":"en"}' ``` If the key is accepted, you'll hear "hello" when you play `hello.mp3`. If it isn't, `--fail` stops curl with a `401` instead of saving the error text as the file. Use the same header for the HTTP, WebSocket, metadata, and utility endpoints. ## CLI authentication The `rime` CLI manages the key locally. Run [`rime login`](/cli-reference/rime-auth) once, and the CLI stores the key at `~/.rime/rime.toml`. You can also set it with the `RIME_CLI_API_KEY` environment variable. ## On-prem authentication Caller authentication depends on the deployment. A standalone licensed engine doesn't authenticate callers, so your gateway must. Its `RIME_API_KEY` only authenticates the engine's usage reports to Rime. In an existing API/model pair, the API service accepts the same `Authorization: Bearer …` header, or you can configure `RIME_API_KEY` for the deployment so callers don't need to send it. See [the on-prem quickstart](/docs/on-prem/quickstart) for details. ## Common auth errors If your request fails authentication, the API returns `401 Unauthorized` with a short plain-text body explaining why: | Status | Body | Cause | | :- | :- | :- | | `401` | `missing headers` | No `Authorization` header was sent. | | `401` | `invalid api key` | The token is not recognized, or it was sent without the `Bearer` scheme. | | `401` | `invalid subscription` | The token is valid, but its account has neither a valid subscription nor a positive balance. Check billing before regenerating the key. | Always send the header as `Authorization: Bearer ` (capital `B`). The token alone, without `Bearer`, is rejected. ## Related * [Quickstart: TTS in five minutes](/docs/quickstart-five-minute) * [API reference index](/docs/api-reference) * [CLI authentication commands](/cli-reference/rime-auth) # API cheat sheet Source: https://docs.rime.ai/docs/api-cheat-sheet Base URLs, bearer authentication, and runnable examples for Rime's HTTP, WebSocket, voice, vocabulary, and text-normalization endpoints. Create a key on the [API Tokens page](https://app.rime.ai/tokens) before running the authenticated examples below. ## Hosts and authentication | What | Where | | - | - | | REST API (TTS, voices, coverage) | `https://users.rime.ai` | | WebSocket API | `wss://users-ws.rime.ai` | | Text normalization | `https://optimize.rime.ai` | | Docs (this site, plus `/llms.txt` and per-page `.md` exports) | `https://docs.rime.ai` | * Send TTS requests to `users.rime.ai`, not `api.rime.ai`. The latter serves internal infrastructure and returns `404` for TTS requests. * Authenticate with `Authorization: Bearer YOUR_API_KEY`. On WebSocket connections, send the same value as a connection header. * Keep the key on a server. Browser `WebSocket` objects cannot set the required header, so browser applications need a server-side bridge. Rime publishes Python [`rime-api`](https://pypi.org/project/rime-api/) and JavaScript [`@rimelabs/api`](https://www.npmjs.com/package/@rimelabs/api) for generated TTS message definitions and schemas. These packages cover the [standalone engine protocol](/docs/on-prem/protocols#python-and-javascript-packages). Your application still manages connections and authentication. The cloud examples below use standard HTTP and WebSocket clients. ## Synthesize speech (HTTP) `POST /v1/rime-tts` returns audio bytes in the format named by your `Accept` header (`audio/mpeg`, `audio/wav`, `audio/webm;codecs=opus`, `audio/ogg;codecs=opus`, `audio/L16`, `audio/PCMU`): ```bash theme={null} curl -X POST https://users.rime.ai/v1/rime-tts \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -H 'Accept: audio/mpeg' \ --output hello.mp3 \ -d '{"text": "Hello from Rime.", "speaker": "astra", "modelId": "coda"}' ``` Full parameters and streaming variants: [Coda HTTP reference](/api-reference/coda/http) · [Streaming guide](/docs/streaming) ## Stream speech (WebSocket `/ws3`) Synthesis arguments go in the query string; auth goes in the connection header. Send `{"text": ...}` messages (buffered by sentence by default) and operations (`{"operation": "flush" | "clear" | "eos"}`); receive JSON events: `chunk` (base64 audio), `timestamps` (word-level), `done`, `error`. ```python theme={null} import asyncio, base64, json, os import websockets # pip install websockets async def main(): url = "wss://users-ws.rime.ai/ws3?speaker=astra&modelId=coda&audioFormat=mp3" headers = {"Authorization": f"Bearer {os.environ['RIME_API_KEY']}"} async with websockets.connect(url, additional_headers=headers) as ws: await ws.send(json.dumps({"text": "Hello from Rime over WebSockets."})) await ws.send(json.dumps({"operation": "eos"})) # synthesize what's buffered, then close audio = b"" async for raw in ws: event = json.loads(raw) if event["type"] == "chunk": audio += base64.b64decode(event["data"]) elif event["type"] == "timestamps": print("words:", event["word_timestamps"]["words"]) elif event["type"] == "done": break with open("output.mp3", "wb") as f: f.write(audio) print(f"saved {len(audio)} bytes to output.mp3") asyncio.run(main()) ``` Set `modelId` explicitly on `/ws3`. Without it, requests are served by the **Mist v3** backend, and speakers outside the Mist v3 catalog fail with a "Speaker not found" error. Message schemas: [Coda WebSocket reference](/api-reference/coda/websockets-json) · Buffering control: [Segmentation](/docs/websockets-segment) · Web-app bridge pattern: [Next.js voice-agent guide](/docs/voice-agent-nextjs#3-stream-over-websockets-when-latency-matters) ## List voices Both voice endpoints are public; no API key required. ```bash theme={null} # Voice names, keyed by modelId then ISO 639-2 language code curl https://users.rime.ai/data/voices/all-v2.json # Full metadata per voice (gender, age, dialect, language, flagship flag, …) curl https://users.rime.ai/data/voices/voice_details.json ``` Choosing a voice: [Voices guide](/docs/voices) · Reference: [List All Voices](/api-reference/data/voices-v2) · [List Voice Details](/api-reference/data/voice-details) ## Check vocabulary coverage (`/oov`) Returns the input words that are **not** in Rime's pronunciation dictionary: ```bash theme={null} curl -X POST https://users.rime.ai/oov \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"text": "hello kubectl blorbify"}' # → ["kubectl","blorbify"] ``` Out-of-dictionary words still get a best-effort pronunciation; to control them, see [Custom pronunciation](/docs/custom-pronunciation). Reference: [Vocabulary Coverage](/api-reference/other/oov) ## Normalize text (`/textnorm`) Preview exactly how numbers, dates, and phone numbers will be spoken. Note the host: `optimize.rime.ai`. ```bash theme={null} curl -X POST https://optimize.rime.ai/textnorm \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"text": "Call 1-800-444-4141 on 3/4/2026"}' # → {"normalized":"Call one, eight hundred, four four four, four one four one on march fourth twenty twenty six"} ``` Guide: [Text normalization](/docs/text-normalization) · Reference: [Text Normalization](/api-reference/other/textnorm) ## Common parameters | Parameter | Values | Notes | | - | - | - | | `speaker` | See [voices](/docs/voices) | Required. Must match the model and language. | | `modelId` | `coda` (flagship), `mistv3` | Set it explicitly. Without one, `/ws3` serves only the Mist v3 voice catalog. | | `text` | string | Up to 1,000 characters per request (HTTP returns `400` "text is too long" beyond that). | | `lang` | `en`/`eng`, `es`/`spa`, `fr`/`fra`, `pt`/`por`, `de`/`ger`, `ja`/`jpn`, `ar`/`ara`, `hi`/`hin` | Must match the speaker's language. | | `audioFormat` (WS) | `wav`, `mp3`, `ogg`, `webm`, `pcm`, `mulaw` | HTTP uses the `Accept` header instead. | | `segment` (WS) | `bySentence` (default), `immediate`, `never` | When synthesis triggers; see [Segmentation](/docs/websockets-segment). | | `samplingRate` | `8000`–`96000`, default `24000` | Values above 24000 are upsampling. | ## Where to go deeper * [API reference index](/docs/api-reference): every endpoint across every model * [WebSocket API overview](/docs/websockets): endpoint comparison, timestamps, interruption handling * [Build a voice agent](/docs/voice-agent-nextjs): complete apps in Next.js, Vite, Express, plain Node, and FastAPI * [Rime CLI](/docs/quickstart-cli) and the [hosted MCP server](/docs/mcp): tooling around this same API # API reference index Source: https://docs.rime.ai/docs/api-reference Index of Rime's TTS HTTP, WebSocket, and metadata endpoints across all supported models. Send TTS requests to `https://users.rime.ai/v1/rime-tts` and authenticate with a bearer token in the `Authorization` header. See [API authentication](/docs/api-authentication). Most clients should start with **Coda**, Rime's flagship model: * [Coda: Streaming HTTP](/api-reference/coda/http) * [Coda: WebSockets (`/ws`)](/api-reference/coda/websockets) * [Coda: WebSockets JSON (`/ws3`)](/api-reference/coda/websockets-json) For the cross-model overview of when to use each WebSocket endpoint, see [WebSocket API Overview](/docs/websockets). ## TTS endpoints by model | Model | Streaming HTTP | WebSocket `/ws` | WebSocket JSON | | - | - | - | - | | **Coda** (flagship) | [HTTP](/api-reference/coda/http) | [/ws](/api-reference/coda/websockets) | [/ws3](/api-reference/coda/websockets-json) | | **Mist v3** | [HTTP](/api-reference/mistv3/http) | [/ws](/api-reference/mistv3/websockets) | [/ws3](/api-reference/mistv3/websockets-json) | | **Mist v2** | [HTTP](/api-reference/mistv2/http) · [SSE](/api-reference/mistv2/sse) | [/ws](/api-reference/mistv2/websockets) | [/ws2](/api-reference/mistv2/websockets-json) | Mist v2 also exposes non-streaming JSON-wrapped formats: [MP3](/api-reference/mistv2/json-mp3), [WAV](/api-reference/mistv2/json-wav), [Opus/OGG](/api-reference/mistv2/json-ogg), [G.711 μ-law](/api-reference/mistv2/json-mulaw). ## Metadata endpoints * [List All Voices](/api-reference/data/voices-v2): `GET /data/voices/all-v2.json` * [List Voice Details](/api-reference/data/voice-details): `GET /data/voices/voice_details.json` ## Utility endpoints * [Coverage (out-of-vocabulary check)](/api-reference/other/oov): `POST /oov` * [Text Normalization](/api-reference/other/textnorm): `POST /textnorm` ## Related * [Quickstart: TTS in five minutes](/docs/quickstart-five-minute) * [Models](/docs/models): comparing Coda and Mist * [Voices](/docs/voices): voice lineup and language support * [Latency tuning](/docs/latency) * [Changelog](/docs/changelog) # Baseten Source: https://docs.rime.ai/docs/baseten Deploy Rime TTS on Baseten's serverless GPU infrastructure. Run Rime's text-to-speech engine in your own [Baseten](https://www.baseten.co/) workspace, on Baseten's autoscaling GPU infrastructure. Each model runs as a single-container deployment: the engine validates its own license and serves TTS directly, with no separate router. ## Get started Ready-to-use deploy configs for Rime's models live in the [`rimelabs/rime-baseten-deploy`](https://github.com/rimelabs/rime-baseten-deploy) repository. Each model directory contains a Baseten/[Truss](https://truss.baseten.co/) `config.yaml` plus a README with full deploy, secrets, and invocation steps. | Model | Directory | | - | - | | Rime Coda v1: flagship expressive TTS | [`rime-coda-v1/`](https://github.com/rimelabs/rime-baseten-deploy/tree/main/rime-coda-v1) | | Rime Mist v3: low-latency conversational | [`rime-mist-v3/`](https://github.com/rimelabs/rime-baseten-deploy/tree/main/rime-mist-v3) | ## Prerequisites Before cloning the deployment repository, contact [help@rime.ai](mailto:help@rime.ai) for engine-image and license access. Your Baseten workspace needs these secrets: * `gcp_rime_service_account` * `rime_license` * `rime_api_key` To deploy: 1. Clone the repo and `cd` into the model directory you want. 2. Set the three required secrets in your Baseten workspace. The per-model README describes each value. 3. Push the config with the [Truss CLI](https://truss.baseten.co/): ```bash theme={null} truss push . ``` 4. Set the autoscaling concurrency target (each replica handles \~10 concurrent requests before a new one is added). See the model README for the exact Management API call. ## Invoke Once deployed, send inference requests to your model's sync endpoint. The Rime API key is baked in via the `rime_api_key` secret, so callers authenticate to Baseten only. This request saves the audio to `output.webm`: ```python theme={null} import requests resp = requests.post( "https://model-.api.baseten.co/environments/production/sync", headers={ "Authorization": f"Api-Key {BASETEN_API_KEY}", "Accept": "audio/webm;codecs=opus", # or audio/pcm, audio/mpeg }, json={ "text": "Natural-sounding, accurately-pronouncing AI TTS built for high-stakes enterprise conversations.", "speaker": "luna", "lang": "en", }, ) resp.raise_for_status() with open("output.webm", "wb") as f: f.write(resp.content) ``` Play `output.webm` to confirm the deployment returns speech. `raise_for_status()` stops the script before it writes the file when Baseten returns an error status. For full setup instructions, including secrets and autoscaling, see the [`rime-baseten-deploy`](https://github.com/rimelabs/rime-baseten-deploy) README for your chosen model. # Cerebrium Source: https://docs.rime.ai/docs/cerebrium Deploy Rime TTS on Cerebrium's serverless infrastructure. Deploy Rime TTS on [Cerebrium](https://www.cerebrium.ai/) with a Rime API key and Cerebrium CLI 1.39.0 or later. The deployment exposes REST and WebSocket interfaces and scales according to the concurrency and replica settings in `cerebrium.toml`. ### Get started 1. Create a Rime account and obtain your API key. 2. Create a secret in Cerebrium named `RIME_API_KEY` with your Rime key. The Cerebrium container uses it to authenticate to the Rime API. 3. Initialize your app with the Cerebrium CLI (v1.39.0 or higher): ```bash theme={null} cerebrium init rime ``` 4. Define your deployment using a `cerebrium.toml` file with the `[cerebrium.runtime.rime]` configuration. Specify your compute resources (e.g., AMPERE\_A10 GPU, memory, CPU), scaling parameters, and region (e.g., `us-east-1`). See [Cerebrium's documentation](https://cerebrium.ai/docs/cerebrium/partner-services/rime) for full implementation details. 5. Deploy with: ```bash theme={null} cerebrium deploy ``` Once deployed, you can send real-time TTS inference requests using either: * REST API, with an endpoint like: ```bash theme={null} https://api.cerebrium.ai/v4//rime ``` Include your Rime API key in the Authorization header and specify your desired speaker, model, and text. * WebSocket interface for streaming audio For full setup instructions, see the [Cerebrium documentation](https://cerebrium.ai/docs/cerebrium/partner-services/rime). # Changelog Source: https://docs.rime.ai/docs/changelog Release notes for Rime's TTS API and on-prem images. ## Rime API changelog Subscribe to the [RSS feed](https://docs.rime.ai/docs/changelog/rss.xml) to get notified of new releases. * The [on-prem quickstart](/docs/on-prem/quickstart) now uses model image tag `20260923` for Coda and Mist v3. * Standalone licensed deployment needs an image reference and runtime license confirmed by Rime for this mode. Follow [Migrate an existing deployment](/docs/on-prem/quickstart#migrate-an-existing-deployment) before you switch from an API/model pair. * On-prem release `20260912` includes these changes since the previously documented tag, `20260801`: * Coda updates to the 1.0.5 model checkpoint and adds voices, including `walnut`, `harrison_mary`, and `cohen_emily`. * Coda bounds long generations at sentence boundaries while preserving audio order within a request. Its maximum audio duration calculation now uses the codec's correct rate, so the configured 180-second limit no longer cuts a generation off at 172.8 seconds. * Mist v3 avoids TensorRT teardown hangs and crashes during shutdown after draining admitted requests. * Keep the service configuration when you update an existing API/model pair to `20260912`. Update both containers together, using the API image and your model's image: * API: `us-docker.pkg.dev/rime-labs/api/service:20260912` * Coda: `us-docker.pkg.dev/rime-labs/coda/v1/coda:20260912` * Mist v3: `us-docker.pkg.dev/rime-labs/mist/v3/omni:20260912` * The [Data and privacy](https://app.rime.ai/data-and-privacy) page in the Rime dashboard now lets you control optional request-data retention for your personal account or team. * Optional retention is disabled by default. Team members can view the setting, and team owners can change it. * If you enable retention, Rime can keep customer content and technical request details to investigate support issues and improve speech quality. This setting does not permit model training. * Arcana retired from the Rime cloud API. Requests using `arcana`, `arcanav2`, or `arcanav3` are now served by Coda. Replace the retired identifier and verify the voice and language pairing with [Remove Arcana model IDs](/docs/migrate-arcana-to-coda). * Release `20260815`: * Improved text normalization, including more consistent tokenization and handling of symbols, fractions, and common numeric expressions. * The [language matrix](/docs/voices#languages) now lists support per model. * Coda serves English, Arabic, French, German, Hindi, Japanese, Portuguese, and Spanish. * Mist v3 serves English, French, German, and Spanish. * The `lang` parameter tables in the [Coda API reference](/api-reference/coda/http) now include Arabic and Hindi. * **Cloud Arcana requests will switch to Coda on August 15, 2026.** * On August 15, cloud Arcana traffic will route to [Coda](/docs/models#coda). Migrate by changing `modelId: arcana` to `modelId: coda`; the API contract is unchanged. Sinhala remains available on Arcana. * **On-prem:** existing Arcana images remain available to pull and run, but will not receive updates or support (including vulnerability patches and text-normalization fixes) after August 15, 2026. * We recommend migrating before August 15 so you can test voices and validate output on your own timeline. Questions? Contact [support@rime.ai](mailto:support@rime.ai). * Rime now hosts a first-party MCP (Model Context Protocol) server at [mcp.rime.ai](https://mcp.rime.ai): * Connect Claude, OpenAI Codex, your IDE, or any MCP-compatible client to browse the voice catalog, check dictionary coverage, preview text normalization, generate speech samples, and scaffold Pipecat or LiveKit integration code. * Catalog and integration tools work without an API key; synthesis and linguistics tools authenticate with your existing Rime API key, sent per request. * See the [MCP quickstart](/docs/mcp) to get connected, and the [MCP server reference](/mcp-reference/overview) for tool-by-tool documentation. * The Speech QA dashboard has been retired from the Rime web app. * Pronunciation features remain fully supported via the API: check dictionary coverage with the [Coverage API](/api-reference/other/oov) and specify custom pronunciations inline with the [Rime phonetic alphabet](/platform/rime-phonetic-alphabet) and `phonemizeBetweenBrackets` (Mist v1/v2). * To request a pronunciation fix or dictionary addition, reach out to your account manager via Slack or email, or contact [sales@rime.ai](mailto:sales@rime.ai). * The `saveOovs` parameter on Mist v1/v2 endpoints remains supported for backward compatibility, but has been removed from the API reference along with the dashboard it reported to. * Newly documented: the [Phonemize API](/api-reference/other/phonemize); post a recording of a word and get back a phonetic string in the Rime phonetic alphabet. * See [Pronunciation control](/platform/pronunciation-control) for an overview of all the ways to control pronunciation. * **Coda** is now available via `modelId: coda`: * New flagship TTS model; sophisticated LLM backbone paired with a dedicated speech inference engine, trained on conversational full-duplex data. * Surpasses prior Rime models and competitor offerings in human-led voice-quality evaluations across naturalness, prosody, and artifact-free output. * Sub-100ms model latency on the GPU engine (self-hosted or on-prem); cloud API users add roughly 25–50ms network round-trip from most of the continental US. See [Regional endpoints](/docs/regional-endpoints). * Multilingual support across English, French, German, Japanese, Portuguese, and Spanish. * Word-level timestamps over the JSON websocket endpoint for text-audio alignment and interruption handling. * Available via the cloud API and on-premises at launch. * **Recommended successor to Arcana** for all existing Arcana traffic; swap `modelId: arcana` for `modelId: coda`. * See the [Coda API reference](/api-reference/coda/http) for details. * API on-prem image `20260424`: * New environment variables for authentication configuration: * `RIME_API_KEY`: pre-configure the API key at the deployment level so callers don't need to include it in each request. Can also be mounted as a secret file at `/secrets/rime_api_key`. * `API_KEY_HEADER`: specify an alternate header name for platforms that intercept the `Authorization` header. * `PLATFORM_API_KEY`: supply a platform API key for authenticated inter-container requests. Can also be mounted as a secret file at `/secrets/platform_api_key`. * Arcana V2, Arcana V3 and Mist V3 release `20260420`. * General performance improvements and bug fixes. * Arcana release `20260404`: * Improved and stabilized text normalization across all supported languages. * Upgrade to `20260404` is recommended. * Mist v3 release `20260404`: * Reached general availability. * General performance improvements across the inference stack for all models. * API on-prem image `20260407`: * Compatible with Mist v3. * Mist v3 is now available via `modelId: mistv3`: * TTFB well below 100ms: a major latency improvement over Mist v2 without sacrificing quality * Popular Mist v2 speakers available, plus 8 Arcana flagship speakers now available as Mist v3 voices * See the [full voice list](/api-reference/data/voices) * Arcana release `20260223`: * v3 (multilingual) * Supported languages: `de`, `en`, `es`, `fr`, `he`, `ja`, `pt`, `si`, `ta`. * General performance improvements and bug fixes. * API on-prem image `20260212`: * Exposes a new json websockets endpoint with WLT (equivalent to the cloud api's `ws3` endpoint) on port 8003 * Arcana v3 `lang` parameter: 2- and 3-letter ISO 639 codes that map to the same language are accepted and normalized (e.g. de, deu, or ger for German; fr, fra, or fre for French). Supported languages: | 639-1 | 639-2/639-3 | Language | | - | - | - | | de | deu, ger | German | | en | eng | English | | es | spa | Spanish | | fr | fra, fre | French | | he | heb | Hebrew | | ja | jpn | Japanese | | pt | por | Portuguese | Any valid ISO 639-1, 639-2, or 639-3 code that maps to one of these languages is accepted. * Regional endpoints available: * `wss://users-east-ws.rime.ai/ws*` offers all the websockets apis currently served served via `wss://users-ws.rime.ai/ws*` and may provide better latency for clients closer to `us-east-1`. * `https://users-east.rime.ai/v1/rime-tts` offers all the same API currently served via `https://users.rime.ai/v1/rime-tts`, and may provide better latency for clients closer to `us-east-1`. * Additionally `https://users-west.rime.ai/v1/rime-tts` offers all the apis currently served via `https://users.rime.ai/v1/rime-tts`, and may provide better latency for clients closer to `us-west-1`. * Arcana now supports JSON websockets with Word-Level-Timestamps: * `wss://users-ws.rime.ai/ws3` and `wss://users-east-ws.rime.ai/ws3` serve the JSON websockets api that now supports both `mist` and `arcana` model classes. * Arcana release `20260204` (Arcana v3): * Added support for languages: English (`lang=eng`), French (`lang=fra`), German (`lang=ger`), Hebrew (`lang=heb`), Japanese (`lang=jpn`), Portuguese (`lang=por`), Spanish (`lang=spa`). * Languages can be specified using either 2-character codes (`en`, `fr`, `de`, `he`, `ja`, `pt`, `es`) or 3-character codes (`eng`, `fra`, `ger`, `heb`, `jpn`, `por`, `spa`). * Arcana now supports the `spell()` function. You can use `spell()` to spell out sequences letter by letter or number by number with Arcana voices. See the [spell function documentation](/docs/spell) for examples. * Arcana release `20260131`: * General performance improvements and bug fixes. * Arcana release `20260124`: * Fixed speaker mapping for English Arcana. * General performance improvements and bug fixes. * API on-prem image `20260123`: * Exposes the binary websockets API on port 8002. This API is equivalent to the [cloud websockets API](/api-reference/mistv2/websockets). * Arcana release `20260122`: * `rime.engine.initial_latency` and `rime.engine.generated_audio_duration` have saner defaults and [can be tuned](/docs/on-prem/metrics). * Added `spell()` support. * General performance improvements and bug fixes. * Arcana release `20260115`: * Fixed an issue where there is static noise for some speakers at the end or in the middle of utterances. * A full set of ORCA headers are now returned for load balancing. * A `/statusz` endpoint is introduced for the model container that contains diagnostics information. * `/livez` now responds with `OK` as soon as the server starts up. * General performance improvements. * Added [Lovable integration guide](/docs/lovable) with template for building voice-enabled apps. * Added [Replit integration guide](/docs/replit) with template for building voice-enabled apps. * Arcana release `20251220`: * An ORCA header, `named_metrics.inference_concurrency_utilization`, is now returned in all HTTP responses. * Emojis are no longer read out. * General reliability updates. * Arcana release `20251213`: * Performance improvements for the English model. * Minimum requirements for NVIDIA drivers reduced to `525.60.13`. * General reliability updates. * API release `20251209`: * Exposes non-JSON WebSockets over port `8002`, allowing for Arcana over WebSockets. * Fixes an issue where `null` values were sent to the model for parameter keys not set by the user. * Arcana release `20251206`: * [OpenTelemetry metrics](/docs/on-prem/metrics#opentelemetry-metrics) are now available in the model images. * Quality and performance improvements. * Arcana release `20251121`: * Fixed an issue with μ-law encoding. * Arcana release `20251120`: * Fixed an issue with audio buffer underrun. * Arcana release `20251119`: * Fixed a startup issue in the `20251118` release. * Arcana release `20251118`: * General improvements. * Arcana release `20251110`: * Separate engine and data package containers for easier deployment. * General reliability improvements. * Mist on-prem model image `us-docker.pkg.dev/rime-labs/mist/v2/en:20251106` released. * Includes performance enhancements and minor fixes. * Mist on-prem model image `us-docker.pkg.dev/rime-labs/mist/v2/en:20251105` released. * Arcana on-prem model images tagged `20251101` release with language updates. * Arcana language update: additional language support and new voices. * Arcana on-prem model images tagged `20251027`: performance improvements. * Documentation on [performance tuning](/docs/on-prem/performance). * Arcana is now available via (non-json) websockets users.rime.ai/ws. * Arcana on-prem images with tag `20251014`: Fixed a bug related to sample rate. * Arcana on-prem images with tag `20251013`: General performance improvements. * Api on-prem image with tag `20251010`: Uses https instead of http in the external calls to rime.optimize.ai to acquire licenses and track usage. * ⚠️ When upgrading to this image you may have to update your firewall settings to account for the new URLs ([see docs](/docs/on-prem/quickstart#firewall-requirements)). * We have made breaking changes in voice details api ([https://users.rime.ai/data/voices/voice\_details.json](https://users.rime.ai/data/voices/voice_details.json)) * In the voice details API, the field `model_id` has been renamed to `modelId` and `name` have been renamed to `speaker` for better clarity. * In the voice details API, the field `region` has been renamed to `dialect` for better clarity. * The `language` field value has been changed from short codes (e.g., `eng`) to human-readable names (e.g., `english`). * A new field `lang` has been added to retain the short language code (e.g., `eng`). * Arcana on-prem images with tag `20250929`: quality improvements. * Arcana on-prem images with tag `20250927`: quality improvements. * Arcana on-prem English image with tag `20250925`: performance improvements and general model stability enhancements. * Added two new Australian flagship voices: * `eucalyptus` * `marlu` * Arcana on-prem images with tag `20250924`: performance improvements. New api onprem image `us-docker.pkg.dev/rime-labs/api/service:20250917` released. * api image now supports multiple model backends. * /health endpoint on the api image now reports model status. * Both `/ws` and `/ws2` support the query param `saveOovs`, allowing tts users to track which words in their text are out-of-vocabulary on the Speech QA dashboard. * Arcana on-prem images from `20250913` now provide better latency and can run on H100 MIG (`3g.40gb`). * Arcana on-prem images from `20250909` now provide `/livez` and `/readyz` endpoints for liveness and readiness checks. * Arcana on-prem images from `20250908` now use 16-bit little endian for PCM and WAV. * Arcana on-prem images from `20250908` now support G-711 μ-law as an audio codec. * Arcana on-prem images from `20250908` now support the `speedAlpha` option for time scaling. * `saveOovs` parameter added to all mistv2 tts endpoints, enabling users to have out-of-vocabulary words logged to their Speech QA dashboard for review and addition to the mist lexicon. * Added French and German language support via the `lang` parameter in WebSocket JSON APIs. The `/ws2` api now has full language parity with the `/ws` and http tts endpoints. * Added Spanish language support via the `lang: spa` parameter in WebSocket JSON APIs. * Enhanced text segmentation with new `segment` parameter: * Added `segment` query parameter with three modes: "immediate", "never", and "bySentence" (default) * Deprecated `immediate` boolean parameter (still supported for backward compatibility) * Improved control over text processing and synthesis timing * The `` command is now available on both the the websockets and websockets-json apis, allowing for immediate audio synthesis of all tokens in the buffer. * We've launched **Arcana**: a new model for expressive, natural voice synthesis. Available now with `modelId: arcana`. * The `lang` ID `spa-mx` has been added. Using this accesses the same spanish languages but uses `pesos` instead of `dolares` for currency. * New `lang: fra` has been added. We now have French voices available on the dashboard and via API. * The `spell()` function now works for Spanish. Try it out! "El nombre se escribe spell(Isabella)." * Fixed a bug where silence information is not processed properly when `pauseBetweenBrackets` is True * The url `demo-api.rime.ai` has been **deprecated**. Please use `demo.rime.ai` instead if you are using the demo API. # Custom pauses Source: https://docs.rime.ai/docs/custom-pauses Insert pauses of specific durations into Mist family synthesis using angle-bracket markers. Custom pauses are supported by **Mist**, **Mist v2**, and **Mist v3**. By default, Rime adds pauses based on sentence punctuation. To set a specific pause, insert its duration in milliseconds inside angle brackets. For example, `<750>` inserts a pause of 750 milliseconds (or .75 seconds). In the second clip below, listen for the longer gap after "wait": | Audio clip | Sentence | | - | - | |