Appearance
Speech
Text to speech, multi-speaker dialogue, voice previews and the pronunciation dictionary.
Speech and dialogue finish within the request: the response already has status: "succeeded". Download the audio with GET /v1/generations/{id}/file and get subtitles with GET /v1/generations/{id}/subtitles.
For a drop-in text-to-speech endpoint that returns audio bytes directly, see Compatible endpoints.
Endpoints:
GET /v1/speech/optionsPOST /v1/speechPOST /v1/dialoguePOST /v1/dialogue/{id}/lines/{index}GET /v1/speech/voices/{voiceId}/previewGET /v1/pronunciationsPOST /v1/pronunciationsDELETE /v1/pronunciations/{id}
Get speech options
GET /v1/speech/options
Lists speech models, formats, library voices, regions, languages, emotions and sound tags.
Response
200 OK
json
{
"models": [
{ "id": "speech", "label": "Cinara Speech", "maxChars": 10000, "creditsPerCharacter": 1 },
{ "id": "speech-hd", "label": "Cinara Speech HD", "maxChars": 10000, "creditsPerCharacter": 2 }
],
"maxTextChars": 50000,
"chunkChars": 4000,
"formats": [
{ "id": "mp3_standard", "label": "MP3 · 128 kbps", "extension": "mp3", "joinable": true },
{ "id": "mp3_high", "label": "MP3 · 256 kbps · 44.1 kHz", "extension": "mp3", "joinable": true },
{ "id": "flac", "label": "FLAC · lossless · 44.1 kHz", "extension": "flac", "joinable": false }
],
"voices": [
{
"id": "mentor",
"title": "Mentor",
"name": "Nathan",
"gender": "male",
"age": "adult",
"description": "The patient teacher who makes hard ideas simple",
"useCases": ["education", "narration"],
"names": { "english": "Nathan", "india": "Raghav", "arabic": "Karim", "spanish": "Javier", "portuguese": "Eduardo", "french": "Antoine", "german": "Stefan", "chinese": "Jun", "japanese": "Hiroshi", "korean": "Sung-min", "indonesian": "Hendra" }
}
],
"regions": [
{ "id": "english", "label": "Global English", "languages": ["English"] },
{ "id": "india", "label": "India", "languages": ["Hindi"] }
],
"useCases": [
{ "id": "narration", "label": "Narration" },
{ "id": "conversational", "label": "Conversational" }
],
"languages": ["auto", "English", "Hindi", "Spanish"],
"emotions": ["auto", "neutral", "happy", "sad", "angry", "fearful", "disgusted", "surprised"],
"interjections": ["laughs", "sighs", "coughs", "clears throat", "gasps", "sniffs", "groans", "yawns"]
}Lists are shortened above. The full values:
| Field | Description |
|---|---|
models | maxChars is the most characters spoken in one part. Longer scripts are split into parts of up to chunkChars and joined. |
maxTextChars | Longest script accepted in one request: 50,000 characters. |
formats | joinable: false means the format can't be joined from parts, so FLAC is limited to 4,000 characters. |
voices | The 17 library voices below. name is the Global English first name; names gives the first name shown per region. |
regions | english, india, arabic, spanish, portuguese, french, german, chinese, japanese, korean, indonesian. |
useCases | narration, conversational, characters, ads, education, social, kids. |
languages | auto, English, Hindi, Spanish, French, Portuguese, German, Arabic, Russian, Japanese, Korean, Chinese, Chinese,Yue, Italian, Turkish, Dutch, Ukrainian, Vietnamese, Indonesian, Thai, Polish, Romanian, Greek, Czech, Finnish, Bulgarian, Danish, Hebrew, Malay, Slovak, Swedish, Croatian, Hungarian, Norwegian, Slovenian, Catalan, Nynorsk, Afrikaans. |
interjections | Sound tags you can write in a script in parentheses, such as (laughs). Subtitles leave them out. |
Library voices
id | Title · name | Gender | Age | Character |
|---|---|---|---|---|
haven | Haven · Claire | female | adult | Soft and steady, the calm voice that reassures |
hearth | Hearth · Margaret | female | senior | A warm grandmother telling stories by the fire |
rise | Rise · Maya | female | young adult | Bright and motivating, the coach in your corner |
spark | Spark · Zoe | female | young adult | Playful and quick, full of fizz |
lullaby | Lullaby · Rosie | female | young adult | Sweet and gentle, made for bedtime stories |
sunny | Sunny · Ivy | female | teen | A light, friendly teen with a smile in her voice |
confetti | Confetti · Poppy | female | young adult | Big, excited energy for launches and ads |
vesper | Vesper · Evelyn | female | senior | Reverent and composed, like evening prayers |
kindred | Kindred · Hannah | female | adult | Easy and approachable, like chatting with a neighbour |
canyon | Canyon · Marcus | male | adult | Low, resonant and cinematic |
mentor | Mentor · Nathan | male | adult | The patient teacher who makes hard ideas simple |
breeze | Breeze · Jake | male | young adult | Relaxed and easy-going, like a podcast chat |
captain | Captain · Ryan | male | adult | Confident and firm; says it like he means it |
velvet | Velvet · Edward | male | adult | Polished and refined, with a gentleman's poise |
monarch | Monarch · Victor | male | senior | Commanding and authoritative, the movie-trailer voice |
valor | Valor · Owen | male | young adult | Heroic and bold, ready for adventure |
scout | Scout · Noah | male | teen | Polite and earnest, the good kid next door |
Every library voice works with both models. Your workspace's own cloned and designed voices can speak too: use their providerVoiceId from GET /v1/voices wherever a voiceId is asked for.
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/speech/options \
-H "Authorization: Bearer $CINARA_API_KEY"Create speech
POST /v1/speech
Speaks a script in one voice and stores the audio as a generation.
Needs a verified phone.
The workspace's pronunciation rules are applied before speaking. Scripts over 4,000 characters are split at paragraph and sentence breaks, spoken in parts and joined into one file.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
text | string | yes | The script. Must not be blank. Up to 50,000 characters. Up to 4,000 with format: "flac". |
model | string | yes | speech or speech-hd. |
voiceId | string | yes | A library voice id (such as mentor), or the providerVoiceId of one of the workspace's cloned or designed voices. |
format | string | no | mp3_standard (default), mp3_high or flac. Any other value falls back to mp3_standard. |
language | string | no | A language from the options list, or auto. Improves pronunciation. |
emotion | string | no | An emotion from the options list. auto lets the model choose. |
speed | number | no | Speaking speed. Default 1. Values are clamped to 0.5–2. |
pitch | number | no | Pitch in semitones. Default 0. Values are clamped to −12 to 12 and rounded. |
Response
201 Created
json
{
"generation": {
"id": "7c1d2e9a-4b6f-4e0a-9d2c-3f8a1b5e6c70",
"module": "speech",
"status": "succeeded",
"input": {
"text": "Welcome to the course. Today we start with the basics.",
"model": "speech",
"voiceId": "mentor",
"format": "mp3_high",
"pronunciations": 0
},
"output": {
"durationMs": 3480,
"contentType": "audio/mpeg",
"extension": "mp3",
"format": "mp3_high",
"hasSubtitles": true
},
"credits": 54,
"error": null,
"created_at": "2026-09-15T10:42:07.512341+00:00",
"completed_at": "2026-09-15T10:42:09.884102+00:00"
},
"credits": 49946
}input.pronunciationsis how many pronunciation replacements were made.output.hasSubtitlessays subtitles can be made for this audio.credits(top level) is the workspace balance after the charge.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Choose a speech model |
| 400 | invalid_request | Enter some text |
| 400 | invalid_request | Text is limited to 50,000 characters |
| 400 | invalid_request | Unknown voice |
| 400 | invalid_request | Unsupported language |
| 400 | invalid_request | Unsupported emotion |
| 400 | invalid_request | Lossless FLAC is available up to 4,000 characters. Use MP3 for longer scripts. |
| 400 | invalid_request | Lossless FLAC is limited to 4,000 characters. Use MP3 for longer scripts. (the script grew past 4,000 characters after pronunciation replacements) |
| 402 | insufficient_credits | This needs 54 credits |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Speech generation failed. Your credits were refunded. |
Credits
max(1, ceil(characters × rate)), where the rate is 1 credit per character for speech and 2 for speech-hd. Characters are counted on text as sent, before pronunciation replacements. Refunded if speaking fails.
Example
bash
ID=$(curl -s -X POST https://api.cinara.ai/v1/speech \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Welcome to the course. Today we start with the basics.", "model": "speech", "voiceId": "mentor", "format": "mp3_high"}' \
| jq -r .generation.id)
curl -L "https://api.cinara.ai/v1/generations/$ID/file" \
-H "Authorization: Bearer $CINARA_API_KEY" -o welcome.mp3Create dialogue
POST /v1/dialogue
Speaks a conversation with a voice per speaker and joins the lines into one file.
Needs a verified phone.
Each line ends with a short pause (about 0.35 s). Pronunciation rules are applied to every line.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model | string | yes | speech or speech-hd. |
lines | array | yes | 1 to 200 lines, in order. |
lines[].speaker | string | yes | The speaker's name. 1–40 characters. |
lines[].text | string | yes | What they say. 1–2,000 characters. |
lines[].emotion | string | no | An emotion from the speech options. auto or omitted lets the model choose. |
lines[].volume | number | no | Loudness multiplier, 0.5–2. Default 1. |
voices | object | yes | A voice id for every speaker name used, for example {"Asha": "haven", "Ben": "breeze"}. Library ids or the workspace's own providerVoiceIds. |
language | string | no | A language from the speech options. Anything else becomes auto. |
speed | number | no | Speaking speed for every line. Default 1. Clamped to 0.5–2. |
All lines together can have up to 50,000 characters.
Response
201 Created
json
{
"generation": {
"id": "c2a9e4f1-6b3d-4c8e-a1f7-9d0b5e2c3a64",
"module": "dialogue",
"status": "succeeded",
"input": {
"lines": [
{ "speaker": "Asha", "text": "Did you hear the thunder last night?" },
{ "speaker": "Ben", "text": "I slept right through it.", "emotion": "happy" }
],
"voices": { "Asha": "haven", "Ben": "breeze" },
"model": "speech-hd",
"language": "auto",
"speed": 1
},
"output": {
"durationMs": 4310,
"contentType": "audio/mpeg",
"extension": "mp3",
"segments": [
{ "index": 0, "speaker": "Asha", "text": "Did you hear the thunder last night?", "start": 0, "end": 2.46 },
{ "index": 1, "speaker": "Ben", "text": "I slept right through it.", "start": 2.46, "end": 4.31 }
],
"hasSubtitles": true
},
"credits": 120,
"error": null,
"created_at": "2026-09-15T11:03:44.201937+00:00",
"completed_at": "2026-09-15T11:03:47.650218+00:00"
},
"credits": 49826
}output.segments gives each line's start and end in seconds, including its trailing pause.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Choose a speech model |
| 400 | invalid_request | Add at least one line |
| 400 | invalid_request | A dialogue can have up to 200 lines |
| 400 | invalid_request | Line 3 needs a speaker name (up to 40 characters) |
| 400 | invalid_request | Line 3 is empty |
| 400 | invalid_request | Line 3 is longer than 2,000 characters |
| 400 | invalid_request | Choose a voice for Ben |
| 400 | invalid_request | Line 3 has an unsupported emotion |
| 400 | invalid_request | Line 3 volume must be between 50% and 200% |
| 400 | invalid_request | A dialogue is limited to 50,000 characters |
| 402 | insufficient_credits | This needs 120 credits |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Dialogue generation failed. Your credits were refunded. |
Credits
max(1, ceil(total characters × rate)) over all lines' text, with the same rates as Create speech. Refunded if it fails.
Example
bash
curl -X POST https://api.cinara.ai/v1/dialogue \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "speech-hd",
"lines": [
{"speaker": "Asha", "text": "Did you hear the thunder last night?"},
{"speaker": "Ben", "text": "I slept right through it.", "emotion": "happy"}
],
"voices": {"Asha": "haven", "Ben": "breeze"}
}'Redo a dialogue line
POST /v1/dialogue/{id}/lines/{index}
Says one line again, optionally with new text, emotion or volume, and re-joins the conversation. Other lines aren't regenerated.
Needs a verified phone.
Path parameters
| Name | Description |
|---|---|
id | A succeeded dialogue generation. |
index | The line's position, starting at 0. |
Request body
All fields are optional. Anything left out keeps the line's current value.
| Field | Type | Description |
|---|---|---|
text | string | New text, up to 2,000 characters. A blank value keeps the current text. |
emotion | string | An emotion from the speech options. auto clears the line's emotion. |
volume | number | Loudness multiplier, 0.5–2. |
Response
200 OK. The updated generation and the new balance. generation.credits grows by the cost of the redo, and input.lines and output.segments reflect the new line.
json
{
"generation": {
"id": "c2a9e4f1-6b3d-4c8e-a1f7-9d0b5e2c3a64",
"module": "dialogue",
"status": "succeeded",
"input": {
"lines": [
{ "speaker": "Asha", "text": "Did you hear the thunder last night?" },
{ "speaker": "Ben", "text": "I slept right through it. Lucky me!", "emotion": "happy" }
],
"voices": { "Asha": "haven", "Ben": "breeze" },
"model": "speech-hd",
"language": "auto",
"speed": 1
},
"output": {
"durationMs": 5020,
"contentType": "audio/mpeg",
"extension": "mp3",
"segments": [
{ "index": 0, "speaker": "Asha", "text": "Did you hear the thunder last night?", "start": 0, "end": 2.46 },
{ "index": 1, "speaker": "Ben", "text": "I slept right through it. Lucky me!", "start": 2.46, "end": 5.02 }
],
"hasSubtitles": true
},
"credits": 190,
"error": null,
"created_at": "2026-09-15T11:03:44.201937+00:00",
"completed_at": "2026-09-15T11:03:47.650218+00:00"
},
"credits": 49756
}Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Dialogue line not found |
| 400 | invalid_request | A line is limited to 2,000 characters |
| 400 | invalid_request | Unsupported emotion |
| 400 | invalid_request | Volume must be between 50% and 200% |
| 402 | insufficient_credits | This needs 70 credits |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Couldn't redo that line. Your credits were refunded. |
Credits
max(1, ceil(characters of the new line × rate)), using the dialogue's model. Refunded if it fails.
Example
bash
curl -X POST "https://api.cinara.ai/v1/dialogue/$ID/lines/1" \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "I slept right through it. Lucky me!"}'Get a voice preview
GET /v1/speech/voices/{voiceId}/preview
Returns a short MP3 of a voice introducing itself.
Needs a verified phone.
- For a library voice, the clip is spoken in the region's language with the region's first name, for example Haven as "Ananya" in Hindi for
india. - For one of the workspace's own voices (its
providerVoiceId), the clip is the preview made when the voice was created.regionis ignored.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
voiceId | path | yes | A library voice id, or a workspace voice's providerVoiceId. |
region | query | no | A region id from the speech options. Default english. |
Response
200 OK with Content-Type: audio/mpeg and Cache-Control: private, max-age=86400.
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Unknown voice or region |
| 403 | phone_unverified | Verify your phone number to start creating. |
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/speech/voices/haven/preview?region=india" \
-H "Authorization: Bearer $CINARA_API_KEY" -o haven-india.mp3List pronunciations
GET /v1/pronunciations
Lists the workspace's pronunciation rules, sorted by term.
Rules apply to speech, dialogue, audiobooks and the compatible text-to-speech endpoint. A rule matches whole words only. Longer terms are replaced first, so "New York City" wins over "New York". Matching ignores case unless the rule is case-sensitive.
Response
200 OK
json
{
"rules": [
{
"id": "e4b1c7a2-3f5d-4a9e-8c6b-1d2f0e7a9b53",
"term": "Cinara",
"replacement": "sin-AH-rah",
"caseSensitive": false,
"createdAt": "2026-09-14T08:15:22.004511+00:00"
}
]
}Each rule has id, term, replacement, caseSensitive and createdAt.
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/pronunciations \
-H "Authorization: Bearer $CINARA_API_KEY"Create a pronunciation
POST /v1/pronunciations
Adds a rule that replaces a word or phrase with how it should be said.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
term | string | yes | The word or phrase as written. 1–100 characters. Unique per workspace, ignoring case. |
replacement | string | yes | How it should be said. 1–200 characters. |
caseSensitive | boolean | no | Match case exactly. Default false. |
Response
201 Created
json
{
"rule": {
"id": "e4b1c7a2-3f5d-4a9e-8c6b-1d2f0e7a9b53",
"term": "Cinara",
"replacement": "sin-AH-rah",
"caseSensitive": false,
"createdAt": "2026-09-15T12:01:09.338120+00:00"
}
}Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Enter a word or phrase (up to 100 characters) |
| 400 | invalid_request | Enter how it should be said (up to 200 characters) |
| 409 | duplicate | "Cinara" already has a pronunciation |
Credits
Free.
Example
bash
curl -X POST https://api.cinara.ai/v1/pronunciations \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"term": "Cinara", "replacement": "sin-AH-rah"}'Delete a pronunciation
DELETE /v1/pronunciations/{id}
Removes a rule.
Response
200 OK
json
{ "ok": true }Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Pronunciation not found |
Credits
Free.
Example
bash
curl -X DELETE "https://api.cinara.ai/v1/pronunciations/e4b1c7a2-3f5d-4a9e-8c6b-1d2f0e7a9b53" \
-H "Authorization: Bearer $CINARA_API_KEY"