Appearance
Voices
The workspace's own voices (cloned and designed), favourites, voice design and voice cloning.
Cinara's library voices are listed by GET /v1/speech/options.
Endpoints:
GET /v1/voicesPATCH /v1/voices/{id}DELETE /v1/voices/{id}GET /v1/voices/{id}/previewGET /v1/voices/favouritesPUT /v1/voices/favourites/{voiceId}DELETE /v1/voices/favourites/{voiceId}GET /v1/voice-design/optionsPOST /v1/voice-designsGET /v1/voice-designs/{id}GET /v1/voice-designs/{id}/previewPOST /v1/voice-designs/{id}/savePOST /v1/voices/consentPOST /v1/voicesGET /v1/voice-clones/{id}
Two ids per voice
A workspace voice has two ids. Use the right one:
| Id | Looks like | Use it for |
|---|---|---|
id | UUID | Managing the voice: PATCH /v1/voices/{id}, DELETE /v1/voices/{id}, GET /v1/voices/{id}/preview, and singing voices. |
providerVoiceId | opaque string | Speaking with the voice: voiceId in speech, dialogue, the compatible text-to-speech path, voice changer, audiobooks, talking avatars, dub revisions, voice previews and favourites. |
providerVoiceId is an opaque string. Don't parse it.
The voice object
json
{
"id": "5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05",
"source": "cloned",
"providerVoiceId": "vc_7f2a9c41e8b3",
"name": "Priya narrator",
"description": "Warm, even delivery for lessons",
"gender": "female",
"prompt": null,
"createdAt": "2026-09-15T09:12:40.118204+00:00",
"consentVerifiedAt": "2026-09-15T09:14:02.551930+00:00"
}| Field | Type | Description |
|---|---|---|
id | string | The voice's UUID. |
source | string | cloned or designed. |
providerVoiceId | string | The id to speak with. |
name | string | Up to 40 characters. |
description | string or null | Up to 120 characters. |
gender | string or null | female, male or null. |
prompt | string or null | For a designed voice, the description it was designed from. |
createdAt | string | When it was created. |
consentVerifiedAt | string or null | For a cloned voice, when its consent statement was verified. |
List workspace voices
GET /v1/voices
Lists the workspace's cloned and designed voices, newest first.
Query parameters
| Name | Required | Description |
|---|---|---|
source | no | cloned or designed to list only one kind. Anything else lists both. |
Response
200 OK
json
{
"voices": [
{
"id": "5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05",
"source": "cloned",
"providerVoiceId": "vc_7f2a9c41e8b3",
"name": "Priya narrator",
"description": "Warm, even delivery for lessons",
"gender": "female",
"prompt": null,
"createdAt": "2026-09-15T09:12:40.118204+00:00",
"consentVerifiedAt": "2026-09-15T09:14:02.551930+00:00"
}
],
"limit": 10,
"creditsPerVoice": 10000,
"minSeconds": 20,
"maxSeconds": 300
}limit, creditsPerVoice, minSeconds and maxSeconds describe voice cloning: up to 10 cloned voices per workspace, 10,000 credits each, recordings of 20 to 300 seconds.
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/voices?source=cloned" \
-H "Authorization: Bearer $CINARA_API_KEY"Update a voice
PATCH /v1/voices/{id}
Renames or re-describes one of the workspace's voices. A cloned voice's consent record never changes.
Request body
Send at least one field.
| Field | Type | Description |
|---|---|---|
name | string | 1–40 characters. |
description | string | Up to 120 characters. An empty string clears it. |
gender | string or null | female, male, or null to clear it. |
Response
200 OK
json
{
"voice": {
"id": "5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05",
"source": "cloned",
"providerVoiceId": "vc_7f2a9c41e8b3",
"name": "Priya, lessons",
"description": "Warm, even delivery for lessons",
"gender": "female",
"prompt": null,
"createdAt": "2026-09-15T09:12:40.118204+00:00",
"consentVerifiedAt": "2026-09-15T09:14:02.551930+00:00"
}
}Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Voice not found |
| 400 | invalid_request | Give the voice a name of up to 40 characters |
| 400 | invalid_request | Keep the description under 120 characters |
| 400 | invalid_request | The voice type must be female or male |
| 400 | invalid_request | Nothing to change |
| 400 | invalid_request | Cinara doesn't name voices after well-known people. |
Credits
Free.
Example
bash
curl -X PATCH "https://api.cinara.ai/v1/voices/5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05" \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Priya, lessons"}'Delete a voice
DELETE /v1/voices/{id}
Deletes one of the workspace's voices, its favourites, and its preview and sample audio. For a cloned voice, the cloning job keeps its consent details.
Response
200 OK
json
{ "ok": true }Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Voice not found |
Credits
Free.
Example
bash
curl -X DELETE "https://api.cinara.ai/v1/voices/5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05" \
-H "Authorization: Bearer $CINARA_API_KEY"Get a workspace voice's preview
GET /v1/voices/{id}/preview
Returns the preview clip of one of the workspace's voices, by its UUID.
Response
200 OK with Content-Type: audio/mpeg and Cache-Control: private, max-age=3600.
For a cloned voice the clip says "Hi, this is name. This is how my voice sounds in Cinara." For a designed voice it's the design's preview.
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Preview not found |
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/voices/5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05/preview" \
-H "Authorization: Bearer $CINARA_API_KEY" -o preview.mp3List favourite voices
GET /v1/voices/favourites
Lists the voice ids the key's creator marked as favourites in this workspace, newest first. Favourites are per member, per workspace.
Response
200 OK
json
{ "voiceIds": ["mentor", "vc_7f2a9c41e8b3", "haven"] }Ids are library voice ids or workspace voices' providerVoiceIds.
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/voices/favourites \
-H "Authorization: Bearer $CINARA_API_KEY"Add a favourite voice
PUT /v1/voices/favourites/{voiceId}
Marks a voice as a favourite. Adding one that's already a favourite succeeds.
Path parameters
| Name | Description |
|---|---|
voiceId | A library voice id, or a workspace voice's providerVoiceId. |
Response
200 OK
json
{ "ok": true }Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Voice not found |
| 400 | invalid_request | You can keep up to 200 favourite voices |
Credits
Free.
Example
bash
curl -X PUT https://api.cinara.ai/v1/voices/favourites/mentor \
-H "Authorization: Bearer $CINARA_API_KEY"Remove a favourite voice
DELETE /v1/voices/favourites/{voiceId}
Removes a voice from favourites. It succeeds even when the voice wasn't a favourite.
Response
200 OK
json
{ "ok": true }Credits
Free.
Example
bash
curl -X DELETE https://api.cinara.ai/v1/voices/favourites/mentor \
-H "Authorization: Bearer $CINARA_API_KEY"Voice design
Voice design turns a description into a new voice with a spoken preview. Each design is a background job. Listen to the preview, then save the designs you like to the workspace's voices. A design must be saved within 7 days.
Get voice design options
GET /v1/voice-design/options
Response
200 OK
json
{
"creditsPerDesign": 20000,
"promptMin": 20,
"promptMax": 2000,
"previewMin": 50,
"previewMax": 500,
"keepDays": 7,
"maxVoices": 30,
"samples": [
{
"id": "conversation",
"label": "Conversation",
"text": "Hey, it's so good to hear from you! I was just thinking about that trip we planned. Are we still going next weekend, or should we wait until the weather gets a little warmer? Either way, I'll bring the snacks."
}
],
"traits": {
"gender": ["female", "male"],
"age": ["child", "teenager", "young adult", "middle-aged", "elderly"],
"accent": ["American", "British", "Australian", "Canadian", "Irish", "Scottish", "Indian", "Nigerian", "South African", "French", "Spanish", "German"],
"pace": ["slow", "measured", "fast"],
"tone": ["warm", "calm", "deep", "bright", "energetic", "gentle", "authoritative", "playful", "raspy", "breathy", "mysterious", "cheerful"]
}
}samples holds ready-made preview texts with the ids story, conversation, advert, character, news, meditation and hindi (shortened above). traits are words that help when writing a description.
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/voice-design/options \
-H "Authorization: Bearer $CINARA_API_KEY"Design a voice
POST /v1/voice-designs
Starts designing a voice from a description.
Needs a verified phone.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | yes | A description of the voice. 20–2,000 characters. Describe the voice itself; naming well-known people is refused. |
previewText | string | yes | What the new voice says in its preview. 50–500 characters. |
Response
201 Created
json
{
"generation": {
"id": "8e3d1b7a-4c2f-4a6e-9b0d-7f5c2a1e3d98",
"module": "voice_design",
"status": "running",
"input": {
"prompt": "An elderly man with a warm, deep voice and a British accent, speaking slowly.",
"previewText": "Come closer and let me tell you a story. Long ago, in a small village by the sea, there lived a fisherman who could hear the waves sing."
},
"output": { "stage": "queued", "step": 1, "stageLabel": "Designing the voice" },
"credits": 20000,
"error": null,
"created_at": "2026-09-15T13:20:11.402113+00:00",
"completed_at": null
},
"credits": 39756
}Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Describe the voice in at least 20 characters |
| 400 | invalid_request | Keep the description under 2,000 characters |
| 400 | invalid_request | The preview text needs at least 50 characters |
| 400 | invalid_request | The preview text can be up to 500 characters |
| 400 | invalid_request | Cinara doesn't design voices that copy well-known people. Describe the voice itself instead. |
| 402 | insufficient_credits | This needs 20,000 credits |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Voice design couldn't start. Your credits were refunded. |
Credits
20,000 credits per design, whether or not you save it. Refunded if the design fails. Saving is free.
Example
bash
curl -X POST https://api.cinara.ai/v1/voice-designs \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "An elderly man with a warm, deep voice and a British accent, speaking slowly.", "previewText": "Come closer and let me tell you a story. Long ago, in a small village by the sea, there lived a fisherman who could hear the waves sing."}'Get a voice design
GET /v1/voice-designs/{id}
Checks a design, moves it forward, and returns it. Poll until status isn't running.
Response
200 OK
json
{
"generation": {
"id": "8e3d1b7a-4c2f-4a6e-9b0d-7f5c2a1e3d98",
"module": "voice_design",
"status": "succeeded",
"input": {
"prompt": "An elderly man with a warm, deep voice and a British accent, speaking slowly.",
"previewText": "Come closer and let me tell you a story. Long ago, in a small village by the sea, there lived a fisherman who could hear the waves sing."
},
"output": {
"design": {
"providerVoiceId": "vd_19c4e2a7b6f0"
}
},
"credits": 20000,
"error": null,
"created_at": "2026-09-15T13:20:11.402113+00:00",
"completed_at": "2026-09-15T13:20:39.771640+00:00"
},
"voice": null,
"expiresAt": "2026-09-22T13:20:11.402Z",
"credits": 39756
}| Field | Description |
|---|---|
voice | The saved voice object, or null until the design is saved. |
expiresAt | The last moment the design can be saved (7 days after it was created). |
credits | The new balance. Present only on the read where the status changed. |
Once saved, output.savedVoiceId holds the voice's UUID.
A failed design has status: "failed" and an error such as Voice design took too long and was stopped. or Voice design failed.
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Not found |
Credits
Free.
Polling example
bash
while :; do
RES=$(curl -s "https://api.cinara.ai/v1/voice-designs/$ID" -H "Authorization: Bearer $CINARA_API_KEY")
[ "$(echo "$RES" | jq -r .generation.status)" != "running" ] && break
sleep 5
done
curl -s "https://api.cinara.ai/v1/voice-designs/$ID/preview" -H "Authorization: Bearer $CINARA_API_KEY" -o design.mp3Get a voice design's preview
GET /v1/voice-designs/{id}/preview
Returns the design's spoken preview.
Response
200 OK with the clip's content type (normally audio/mpeg) and Cache-Control: private, max-age=3600.
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Preview not found |
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/voice-designs/8e3d1b7a-4c2f-4a6e-9b0d-7f5c2a1e3d98/preview" \
-H "Authorization: Bearer $CINARA_API_KEY" -o design.mp3Save a voice design
POST /v1/voice-designs/{id}/save
Saves a finished design to the workspace's voices, where speech, dialogue, voice changer and the other features can use it.
Needs a verified phone.
Saving a design that's already saved returns the existing voice with 200.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | 1–40 characters. |
description | string | no | Up to 120 characters; longer is refused. Defaults to the first 120 characters of the design's prompt. |
gender | string | no | female or male. |
A workspace can have up to 30 designed voices.
Response
201 Created (or 200 OK when already saved)
json
{
"voice": {
"id": "d71f0c3e-8a2b-4e5d-b6c9-0a4e1f7b2c85",
"source": "designed",
"providerVoiceId": "vd_19c4e2a7b6f0",
"name": "Old storyteller",
"description": "An elderly man with a warm, deep voice and a British accent, speaking slowly.",
"gender": "male",
"prompt": "An elderly man with a warm, deep voice and a British accent, speaking slowly.",
"createdAt": "2026-09-15T13:25:02.019873+00:00",
"consentVerifiedAt": null
}
}Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Not found |
| 400 | invalid_request | This design isn't ready yet. |
| 410 | expired | Designs must be saved within 7 days. Generate this one again to save it. |
| 400 | invalid_request | Give the voice a name of up to 40 characters |
| 400 | invalid_request | Keep the description under 120 characters |
| 400 | invalid_request | Cinara doesn't design voices that copy well-known people. |
| 400 | invalid_request | A workspace can have up to 30 designed voices. Delete one to save another. |
| 404 | not_found | The preview is missing. Generate the voice again. |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Couldn't save the voice. Try again in a moment. |
Credits
Free. The design was already paid for.
Example
bash
curl -X POST "https://api.cinara.ai/v1/voice-designs/8e3d1b7a-4c2f-4a6e-9b0d-7f5c2a1e3d98/save" \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Old storyteller", "gender": "male"}'Voice cloning
A voice is cloned only from a recording that starts with a one-time consent statement, read aloud by the person whose voice it is. This stops cloning someone from recordings that already exist.
The flow:
- Get a statement.
POST /v1/voices/consentwith the speaker's full name. You get achallengeIdand aphrase. It expires after 30 minutes and works for one recording. - Record. The speaker reads the phrase word for word, including the code words, then keeps talking naturally. Only that one person should be heard. The recording needs at least 20 seconds and can be up to 5 minutes.
- Upload the recording with
/v1/uploads. It must be an audio file. - Clone.
POST /v1/voiceswith the upload'skey, thechallengeId, a name andattested: true. - Poll
GET /v1/voice-clones/{id}until it finishes. The response then includes the new voice.
The consent check passes when:
- every code word is heard, in order;
- at least 80% of the statement's words are heard, in order (small misspellings are allowed);
- only one speaker is heard (a speaker counts when they say at least 15% of the words);
- the speech heard lasts at least 20 seconds.
Names of well-known people are refused in the speaker name, voice name and description.
Get a consent statement
POST /v1/voices/consent
Creates a one-time consent statement for a speaker to read.
Needs a verified phone.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
speakerName | string | yes | The speaker's full name. At least 2 characters. Longer than 60 characters is cut to 60. |
Response
201 Created
json
{
"challengeId": "b3c8e1f4-7a2d-4e9b-8c5a-2f6d0e9b1a37",
"phrase": "My name is Priya Raman. I agree to let Cinara create a digital copy of my voice. My one-time code is lantern cobalt meadow violin.",
"expiresAt": "2026-09-15T09:40:00.000Z"
}The phrase always has this form: My name is <speakerName>. I agree to let Cinara create a digital copy of my voice. My one-time code is <four code words>.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Enter the speaker's full name |
| 400 | invalid_request | Cinara doesn't clone the voices of well-known people. |
| 403 | phone_unverified | Verify your phone number to start creating. |
Credits
Free.
Example
bash
curl -X POST https://api.cinara.ai/v1/voices/consent \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"speakerName": "Priya Raman"}'Clone a voice
POST /v1/voices
Starts cloning a voice from an uploaded recording that begins with the consent statement.
Needs a verified phone.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
attested | boolean | yes | Must be true: you are this speaker, or have their permission. |
key | string | yes | The storage key of a finished upload in this workspace. Must be an audio file. |
challengeId | string | yes | From Get a consent statement. Must be unused, unexpired, and created by the same member (the key's creator) in this workspace. |
name | string | yes | The voice's name. Longer than 40 characters is cut to 40. |
durationSeconds | number | yes | The recording's length in seconds. 20–300. |
description | string | no | Longer than 120 characters is cut to 120. |
gender | string | no | female or male. |
removeNoise | boolean | no | Reduce background noise before cloning. Default false. |
fileName | string | no | A display name for the recording. Up to 200 characters. Defaults to the upload's file name. |
A workspace can have up to 10 cloned voices.
Response
201 Created
json
{
"generation": {
"id": "1f9c5e2a-3b7d-4a8c-9e6f-0d2b4c7a1e59",
"module": "voice_clone",
"status": "running",
"input": {
"key": "workspaces/3f6b2a1c-8d4e-4b7a-9c2d-5e1f0a9b8c7d/uploads/4c1a7e3b-9d2f-4b8e-a6c0-5e3f1d9b7a24/priya-consent.m4a",
"fileName": "priya-consent.m4a",
"contentType": "audio/mp4",
"size": 1843200,
"durationSeconds": 74.2,
"name": "Priya narrator",
"description": "Warm, even delivery for lessons",
"gender": "female",
"speakerName": "Priya Raman",
"challengeId": "b3c8e1f4-7a2d-4e9b-8c5a-2f6d0e9b1a37",
"removeNoise": false
},
"output": { "stage": "queued", "step": 1, "stageLabel": "Checking the consent statement" },
"credits": 10000,
"error": null,
"created_at": "2026-09-15T09:13:21.660419+00:00",
"completed_at": null
},
"credits": 44756
}Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Confirm that you are this speaker, or have their permission. |
| 400 | invalid_request | Upload the recording first |
| 400 | invalid_request | Give the voice a name |
| 400 | invalid_request | Cinara doesn't clone the voices of well-known people. |
| 400 | invalid_request | The recording needs at least 20 seconds: the statement, then natural speech. |
| 400 | invalid_request | Recordings can be up to 5 minutes |
| 400 | invalid_request | This consent statement has expired or was already used. Get a new one. |
| 400 | invalid_request | A workspace can have up to 10 cloned voices. Delete one to make another. |
| 404 | not_found | That upload isn't finished. Upload the recording again. |
| 400 | invalid_request | Upload an audio recording |
| 400 | invalid_request | This consent statement was already used. Get a new one. |
| 402 | insufficient_credits | This needs 10,000 credits |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | generation_failed | Voice cloning couldn't start. Your credits were refunded. |
If the request fails with 402 or 502, the consent statement is released and can be used again.
Credits
10,000 credits per cloned voice. Refunded if the consent check or cloning fails. Speaking with the voice afterwards costs normal speech credits.
Example
bash
curl -X POST https://api.cinara.ai/v1/voices \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attested": true,
"key": "workspaces/3f6b2a1c-8d4e-4b7a-9c2d-5e1f0a9b8c7d/uploads/4c1a7e3b-9d2f-4b8e-a6c0-5e3f1d9b7a24/priya-consent.m4a",
"challengeId": "b3c8e1f4-7a2d-4e9b-8c5a-2f6d0e9b1a37",
"name": "Priya narrator",
"gender": "female",
"durationSeconds": 74.2
}'Get a voice cloning job
GET /v1/voice-clones/{id}
Checks a cloning job, moves it forward, and returns it. Poll until status isn't running.
Steps: checking the consent statement, preparing the recording (for formats other than MP3, WAV and M4A), creating the voice, saving the voice.
Response
200 OK
json
{
"generation": {
"id": "1f9c5e2a-3b7d-4a8c-9e6f-0d2b4c7a1e59",
"module": "voice_clone",
"status": "succeeded",
"input": {
"key": "workspaces/3f6b2a1c-8d4e-4b7a-9c2d-5e1f0a9b8c7d/uploads/4c1a7e3b-9d2f-4b8e-a6c0-5e3f1d9b7a24/priya-consent.m4a",
"fileName": "priya-consent.m4a",
"contentType": "audio/mp4",
"size": 1843200,
"durationSeconds": 74.2,
"name": "Priya narrator",
"description": "Warm, even delivery for lessons",
"gender": "female",
"speakerName": "Priya Raman",
"challengeId": "b3c8e1f4-7a2d-4e9b-8c5a-2f6d0e9b1a37",
"removeNoise": false
},
"output": {
"voiceId": "5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05",
"consent": { "matchedShare": 0.958, "codeHeard": true, "speakers": 1, "heardSeconds": 72.9 },
"step": 2
},
"credits": 10000,
"error": null,
"created_at": "2026-09-15T09:13:21.660419+00:00",
"completed_at": "2026-09-15T09:14:02.551930+00:00"
},
"voice": {
"id": "5a0e3c7b-91d2-4f68-b3a4-6c2e8d1f9b05",
"source": "cloned",
"providerVoiceId": "vc_7f2a9c41e8b3",
"name": "Priya narrator",
"description": "Warm, even delivery for lessons",
"gender": "female",
"prompt": null,
"createdAt": "2026-09-15T09:14:02.201187+00:00",
"consentVerifiedAt": "2026-09-15T09:14:02.551930+00:00"
},
"credits": 44756
}output.voiceIdis the new voice's UUID, not the id to speak with. Usevoice.providerVoiceIdto speak.output.consentshows the check: share of the statement heard, whether the code was heard, speakers heard, and seconds of speech heard.voiceisnulluntil the voice is saved.
If the consent check fails, status is failed, output.consent shows the check and error is one of:
The one-time code wasn't heard. Read the whole statement aloud, including the code words, then keep talking.The consent statement wasn't read clearly enough. Read it word for word, then keep talking.More than one voice was heard. Record only the person whose voice is being cloned.Keep talking for at least 20 seconds in total, so there's enough of the voice to clone.The consent statement is missing. Start again.
Other failures: Voice cloning took too long and was stopped., This file couldn't be read. Try MP3, WAV, M4A, MP4 or WebM., Voice cloning failed.
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Not found |
Credits
Free to read.
Polling example
bash
while :; do
RES=$(curl -s "https://api.cinara.ai/v1/voice-clones/$ID" -H "Authorization: Bearer $CINARA_API_KEY")
STATUS=$(echo "$RES" | jq -r .generation.status)
[ "$STATUS" != "running" ] && break
echo "$(echo "$RES" | jq -r .generation.output.stageLabel)…"
sleep 5
done
echo "$RES" | jq '{status: .generation.status, error: .generation.error, speakWith: .voice.providerVoiceId}'