Appearance
Cinara API reference
The Cinara API lets your own apps and scripts use Cinara: speech, voices, music, sound effects, transcription, audio tools, images, video, dubbing, audiobooks and Drive.
This page covers what every endpoint shares. Each area has its own page:
| Page | What it covers |
|---|---|
| Speech | Text to speech, dialogue, pronunciations, voice previews |
| Voices | Your voices, favourites, voice design, voice cloning |
| Singing | Singing voices and songs sung in a voice |
| Music | Songs, instrumentals and lyrics |
| Sound effects | Sound effects from text and for videos |
| Transcription | Transcripts, alignments, exports and subtitles |
| Audio tools | Clean audio and voice changer |
| Images | Image generation and editing |
| Video | Video clips and talking avatars |
| Dubbing | Dubbing into other languages |
| Studio | Audiobooks |
| Drive | Files, folders and share links |
| History | Generations, generated files, subtitles, your account |
| Uploads | Uploading media before you use it |
| Compatible endpoints | Drop-in text to speech, alignment, speech to text and sound effects |
Base URL
https://api.cinara.aiAll endpoints except /health are under /v1.
GET /health returns {"ok": true}. It needs no key.
Authentication
Every /v1 request needs an API key. Send it in either header:
Authorization: Bearer cin_…xi-api-key: cin_…A key is cin_ followed by 40 letters and digits.
- Getting a key. Create keys in the Cinara app, on the API Keys page. Only workspace owners and admins can create or revoke keys. The full key is shown once. A workspace can have up to 20 active keys.
- Keys can't manage keys. Listing, creating and revoking keys needs a signed-in session in the app. A request made with a key gets
403. - Who a key acts as. A key acts as the member who created it, in the key's own workspace. It spends that workspace's credits. Everything it makes is listed in History with the key's name.
- When a key stops working. A revoked key gets
401. If the member who created the key leaves the workspace, the key gets403.
bash
curl https://api.cinara.ai/v1/me \
-H "Authorization: Bearer $CINARA_API_KEY"Verified phone
Endpoints that create or spend (generations, uploads, share links) need the key's creator to have a verified phone number on their Cinara account. Without one they return:
json
{ "error": "phone_unverified", "message": "Verify your phone number to start creating." }with status 403. Each endpoint's section says Needs a verified phone when this applies. Verify the phone in the Cinara app.
Calling from a browser
CORS only allows Cinara's own web app. Call the API from your server or scripts, not from web pages on other sites.
Browser requests from Cinara's app can send the key in Authorization or xi-api-key, and can read the Retry-After, X-Generation-Id and X-Credits-Remaining response headers.
Clients and User-Agent
If a request is refused with 403 and the body error code: 1010, the HTTP client's default User-Agent was blocked. This has happened with Python's built-in urllib (Python-urllib/*). Send your own User-Agent header, such as my-app/1.0.
Rate limit
Each key can make up to 120 requests per calendar minute. The count is per key. Every request counts, including polling.
Past the limit the API returns 429:
json
{
"error": "rate_limited",
"message": "Too many requests with this API key (up to 120 a minute). Wait a minute and try again.",
"detail": { "status": "rate_limited", "message": "Too many requests with this API key (up to 120 a minute). Wait a minute and try again." }
}The Retry-After header gives the seconds left in the current minute.
Because windows are calendar minutes, a key can make up to 240 requests in a few seconds across a minute boundary.
Requests and responses
- Send JSON bodies with
Content-Type: application/json, unless an endpoint says otherwise (upload parts and some compatible endpoints). - On most endpoints a body that isn't valid JSON is treated as an empty object, so you get the validation error for the first missing field. The JSON compatible endpoints return
400instead. - Responses are JSON unless the endpoint returns a file (audio, video, subtitles, exports).
- Request and response fields are camelCase. Generation objects use snake_case for
created_atandcompleted_at. - Text fields are trimmed. One-line fields (names, prompts) also have control characters removed and runs of spaces collapsed.
- Model and voice ids from earlier versions of Cinara are still accepted and are returned under today's ids.
Errors
Errors are JSON with an error code and a readable message:
json
{ "error": "invalid_request", "message": "Choose a speech model" }Only the compatible endpoints and the 429 rate-limit response also include a detail object: { "status": <error code>, "message": <message> }. Other errors never have one.
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_request | A field is missing or not allowed. The message says which. |
| 401 | unauthorized | No key, or the key isn't valid or has been revoked. |
| 402 | insufficient_credits | The workspace doesn't have enough credits. See Credits. |
| 403 | forbidden | The key's creator no longer has access to the workspace, or a key tried to manage keys. |
| 403 | phone_unverified | The key's creator hasn't verified a phone. |
| 404 | not_found | The item doesn't exist in this workspace, or isn't ready. |
| 409 | duplicate, upload_expired, unavailable, invalid_request | A conflict with the item's current state. |
| 410 | expired | The item can no longer be used (for example an unsaved voice design older than 7 days). |
| 413 | too_large | The file is too big. |
| 422 | unavailable, alignment_failed | The request was understood but couldn't be completed. |
| 429 | rate_limited | Too many requests with this key. |
| 500 | internal | Something went wrong on Cinara's side. Message: Something went wrong. Please try again. |
| 502 | generation_failed | The work couldn't start or failed. Reserved credits are refunded. |
| 503 | unavailable | The feature isn't available right now. |
Endpoint pages list the specific messages each endpoint returns.
The generation object
Everything Cinara makes is a generation. Most create endpoints return one:
json
{
"generation": {
"id": "0b8f6d2e-5c1a-4e7b-9f3d-2a6c8e1b4d70",
"module": "music",
"status": "running",
"input": { "kind": "song", "tier": "standard", "style": "Upbeat modern pop, bright female vocals", "…": "…" },
"output": { "stage": "queued", "step": 1, "stageLabel": "Composing" },
"credits": 2400,
"error": null,
"created_at": "2026-09-15T10:42:07.512341+00:00",
"completed_at": null
},
"credits": 47600
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | The generation's id. Use it to poll and to download files. |
module | string | Which feature made it, for example speech, music, dubbing. |
status | string | running, succeeded or failed. |
input | object | What was asked for, as Cinara stored it. |
output | object | Progress while running; results once finished. Shape depends on the feature. |
credits | integer | Credits reserved while running; the final charge once finished. |
error | string or null | A readable reason when status is failed. |
created_at | string | When it was created (ISO 8601). |
completed_at | string or null | When it finished. |
The top-level credits next to generation is the workspace's credit balance after the request.
What responses leave out
input and output show what you asked for and what was made, not how Cinara made it. Storage paths, links to outside services, job tickets, work bookkeeping and internal costs are left out of every job response, History (GET /v1/generations), GET /v1/generations/{id} and the MCP server. Two things are kept:
- The
keyof your own uploads, which you can send again. - An image made in Images, shown as
{ "generationId": …, "file": … }: the same form the image and video endpoints accept.
Finished files always come as signed links in files.
Async jobs
Most features run in the background:
- Start.
POSTthe create endpoint. It reserves credits and returns201with a generation whosestatusisrunning. - Poll.
GETthe job endpoint (for exampleGET /v1/music/{id}). Each read checks the work once, moves it forward, and returns the current state. - Finish. When
statusissucceeded, the response includes the results. When it'sfailed,errorsays why and the credits are refunded.
Keep polling until the job finishes. Jobs move forward when they're read. Dubbing and audiobooks do a bounded piece of work on each read, so they only progress while you poll. A job still unfinished after 3 hours is stopped and refunded the next time it's read.
While running, output usually has:
| Field | Description |
|---|---|
stage | queued or processing (Transcribe uses queued or transcribing). |
stageLabel | A readable step name, such as Composing or Checking the lyrics. |
step | The current step number, for jobs with several steps. input.totalSteps gives the total where it exists. |
A job response includes a top-level credits (the new balance) only on the read where the status changed.
Poll a few seconds apart. Every poll counts toward the rate limit.
bash
# Start a job
ID=$(curl -s -X POST https://api.cinara.ai/v1/music \
-H "Authorization: Bearer $CINARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind": "instrumental", "style": "Lo-fi hip hop, soft piano, mellow bass, 80 BPM", "seconds": 60}' \
| jq -r .generation.id)
# Poll until it finishes
while :; do
RES=$(curl -s "https://api.cinara.ai/v1/music/$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, files: .files}'Some endpoints finish within the request instead: speech, dialogue, lyrics and the compatible endpoints.
When a request's wait runs out
The compatible speech to text, forced alignment and sound effect endpoints wait for their result. If the work is still running when the wait ends, they return 202 Accepted with an X-Generation-Id header:
json
{ "status": "processing", "generation_id": "a1d6f3b8-7c2e-4b9a-8e5d-3f0c6a2b9e14" }The work carries on and isn't refunded. Poll GET /v1/generations/{id} until status isn't running.
Files
A finished job response lists its files:
json
"files": [
{
"name": "song",
"label": "Midnight Drive",
"contentType": "audio/mpeg",
"size": 2841600,
"url": "https://api.cinara.ai/media/1789511327/k3JH9…/workspaces/…/song.mp3"
}
]| Field | Description |
|---|---|
name | The file's name within the job, used by the download route. |
label | A readable label. |
contentType | The file's media type. |
size | Size in bytes. |
url | A signed link that works without a key. It expires after 6 hours. It supports HTTP Range requests. |
Signed links are fresh on every read, so read the job again to get a new link. GET /v1/generations/{id} returns fresh links for any generation, including speech and dialogue.
To download with your key instead, use the feature's download route, for example:
GET /v1/music/{id}/files/{name}It returns the file with Content-Disposition: attachment and a readable file name. It returns 404 File not found until the job has succeeded.
bash
curl -L "https://api.cinara.ai/v1/music/$ID/files/instrumental" \
-H "Authorization: Bearer $CINARA_API_KEY" -o instrumental.mp3Speech and dialogue audio is downloaded with GET /v1/generations/{id}/file.
Credits
Every generation costs credits. Each endpoint's Credits section gives its rule.
Reserve. Credits are reserved when the work starts. If the workspace doesn't have enough, the request fails with
402:json{ "error": "insufficient_credits", "message": "This needs 2,400 credits" }Settle. Some features charge by what was actually made (for example transcription minutes or the length of a song). When they finish, the difference is refunded, or the extra is charged. If the extra can't be charged, the reserve stands.
Refund. If a job fails, its reserved credits are refunded.
Balance.
GET /v1/mereturns the balance. Many responses also include it ascredits.What each generation cost.
GET /v1/generationsreturnschargedper row: the net cost after refunds.Free. Options endpoints, reading jobs, downloads, History, Drive, pronunciations and voice management are free.
Uploading media
Features that work on your own files (transcription, clean audio, voice changer, voice cloning, dubbing, image edits, video from an image and more) take the storage key of a finished upload, not the file itself.
POST /v1/uploadswith the file's name, type and size. You get akey, anuploadId, and how to split the file.PUT /v1/uploads/partfor each part (10 MB each, except the last).POST /v1/uploads/completewith the part numbers and etags.- Pass the
keyto the feature, for example{"key": "workspaces/…/uploads/…/interview.mp3"}.
Files can be up to 2 GB; images up to 20 MB. See Uploads for the full flow and a script.
Many features also take an optional durationSeconds. Send the file's real length when you know it: for several features it sets the credit charge. When it's missing, the length is estimated from the file size.
Pagination
Two list endpoints page with a cursor:
| Endpoint | Page size | Cursor |
|---|---|---|
GET /v1/generations | limit, 1 to 100, default 50 | before = the previous page's nextBefore |
GET /v1/drive | 100 files | before = the previous page's nextBefore |
nextBefore is null on the last page. Other lists return everything at once.
Options endpoints
Most areas have a free GET …/options endpoint that returns the current models, limits, languages and credit rates. Read it instead of hard-coding limits:
GET /v1/speech/optionsGET /v1/transcribe/optionsGET /v1/clean-audio/optionsGET /v1/voice-changer/optionsGET /v1/voice-design/optionsGET /v1/sound-effects/optionsGET /v1/music/optionsGET /v1/images/optionsGET /v1/video/optionsGET /v1/avatars/optionsGET /v1/dubbing/optionsGET /v1/studio/optionsGET /v1/singing-voices(includes singing limits)
Content rules
Cinara refuses requests that name well-known people in prompts, voice names and similar fields, with a 400 and a message such as Cinara doesn't make images of well-known people. Describe the scene without naming them. Voice cloning also needs a spoken consent statement; see Voices.
MCP server and OpenAPI spec
The same API is available to AI assistants:
- MCP server:
POST https://api.cinara.ai/v1/mcp, stateless Streamable HTTP, with the same API key headers. It offers 13 tools for speech, dialogue, sound effects, lyrics, music, images, video, History and Drive. Its calls count toward the key's rate limit, and one tool call can make several requests while it waits for a job. - OpenAPI spec:
GET https://api.cinara.ai/openapi.json, no key needed. It describes 20 operations with bearer authentication, sized for ChatGPT's GPT Actions.
See Integrations to connect Claude, ChatGPT, VS Code or Cursor.