Appearance
History
Everything the workspace has made, from the app and from API keys, plus downloads and subtitles for generated audio, and the current account.
Endpoints:
GET /v1/generationsGET /v1/generations/{id}GET /v1/generations/{id}/fileGET /v1/generations/{id}/subtitlesGET /v1/me
List generations
GET /v1/generations
Lists the workspace's generations, newest first, a page at a time.
Reading History doesn't move background jobs forward. To advance a running job, read it through its feature's endpoint.
Query parameters
| Name | Required | Description |
|---|---|---|
module | no | Only this feature. See the module list below. |
source | no | app for items made in the Cinara app, api for items made with any API key. Ignored when apiKeyId is given. |
apiKeyId | no | Only items made with this key (UUID). |
before | no | The previous page's nextBefore. |
limit | no | Page size, 1–100. Default 50. |
Modules: speech, dialogue, transcribe, alignment, clean_audio, voice_changer, voice_clone, voice_design, sound_effects, music, music_lyrics, images, video, avatar, dubbing, studio, singing_recording, singing_training, singing.
Response
200 OK
json
{
"generations": [
{
"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",
"playable": true,
"charged": 54,
"apiKey": { "id": "b1e7c3a9-5d2f-4a8e-9c6b-0f3d7a1e5b42", "name": "Course videos" }
},
{
"id": "1f9c5e2a-3b7d-4a8c-9e6f-0d2b4c7a1e59",
"module": "voice_clone",
"status": "failed",
"input": { "name": "Priya narrator", "durationSeconds": 74.2, "…": "…" },
"output": { "stage": "queued", "step": 1, "stageLabel": "Checking the consent statement", "consent": { "matchedShare": 0.42, "codeHeard": false, "speakers": 1, "heardSeconds": 70.1 }, "hasSubtitles": false },
"credits": 10000,
"error": "The one-time code wasn't heard. Read the whole statement aloud, including the code words, then keep talking.",
"created_at": "2026-09-15T09:02:11.004218+00:00",
"completed_at": "2026-09-15T09:02:40.991306+00:00",
"playable": false,
"charged": 0,
"apiKey": null
}
],
"nextBefore": "2026-09-15T09:02:11.004218+00:00",
"apiKeys": [
{ "id": "b1e7c3a9-5d2f-4a8e-9c6b-0f3d7a1e5b42", "name": "Course videos", "revoked": false }
]
}Each row is a generation object plus:
| Field | Type | Description |
|---|---|---|
output.hasSubtitles | boolean | Added to every row. For speech and dialogue, subtitles can be made. |
playable | boolean | The row has audio that GET /v1/generations/{id}/file can return. |
charged | integer | What it actually cost after refunds and settlements (never below 0). credits alone can show a reserve that was refunded. |
apiKey | object or null | The key it was made with: { id, name }. name is Deleted key if the key no longer exists. null for items made in the app. |
| Field | Description |
|---|---|
nextBefore | Pass as before for the next page. null on the last page. |
apiKeys | The workspace's API keys, newest first, with revoked set for revoked keys. For filters. |
Like every other endpoint, rows leave out storage paths and internal details. See What responses leave out.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Unknown API key (not a UUID) |
| 400 | invalid_request | That page of History can't be found (bad before) |
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/generations?source=api&module=speech&limit=20" \
-H "Authorization: Bearer $CINARA_API_KEY"Read every page:
bash
BEFORE=""
while :; do
PAGE=$(curl -s "https://api.cinara.ai/v1/generations?limit=100${BEFORE:+&before=$(jq -rn --arg b "$BEFORE" '$b|@uri')}" \
-H "Authorization: Bearer $CINARA_API_KEY")
echo "$PAGE" | jq -r '.generations[] | "\(.created_at) \(.module) \(.status) \(.charged)"'
BEFORE=$(echo "$PAGE" | jq -r '.nextBefore // empty')
[ -z "$BEFORE" ] && break
doneGet a generation
GET /v1/generations/{id}
Returns any generation in the workspace by id, with fresh signed links to its files. It works for every feature, including speech and dialogue, so it's the simplest way to get a new link once an old one has expired.
- Background jobs (sound effects, music, images, video, transcripts, dubbing and so on) are read through the feature's own job endpoint. Like that endpoint, reading a running job moves it forward, so you can poll here instead.
- Speech and dialogue return a link to their audio.
Long text in the response, such as scripts and transcripts, is shortened to 1,000 characters (ending ...), and lists to 100 items (ending ...and N more). Use the feature's own endpoint for the full result.
Response
200 OK
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.104220+00:00"
},
"files": [
{
"name": "audio",
"label": "Speech",
"contentType": "audio/mpeg",
"size": 25964,
"url": "https://api.cinara.ai/media/1789532529/Qm9v…/workspaces/…/speech.mp3"
}
],
"linksExpireAt": "2026-09-15T16:42:10.000Z"
}| Field | Description |
|---|---|
generation | The generation object. |
files | The generation's files, each with a signed url (see Files). Empty while a job is running, and for results without files. Speech and dialogue have one file, audio. |
linksExpireAt | When the links in files stop working, about 6 hours from now. null when there are no files. |
voice | For voice cloning and voice design jobs, the voice, as the feature's own endpoint returns it. |
credits | The workspace's credit balance, on the read where a background job's status changed. |
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Generation not found |
A background job's own errors are passed through as that job's endpoint returns them.
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/generations/7c1d2e9a-4b6f-4e0a-9d2c-3f8a1b5e6c70" \
-H "Authorization: Bearer $CINARA_API_KEY"Download a generation's audio
GET /v1/generations/{id}/file
Returns a generation's audio. This is how you download speech and dialogue.
What it returns:
- For a succeeded generation, its main audio file: speech and dialogue audio, or the first audio file of a multi-file result (for example a music track or the first sound effect take).
- For a transcription (
transcribe), the uploaded file that was transcribed.
Images and videos aren't returned here. Use the feature's /files/{name} route instead.
Response
200 OK with the file and:
| Header | Value |
|---|---|
Content-Type | The file's type, such as audio/mpeg |
Content-Length | Size in bytes |
Cache-Control | private, max-age=3600 |
Content-Disposition | inline; filename="cinara-<module>-<first 8 characters of id>.<extension>" |
Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | File not found |
Credits
Free.
Example
bash
curl -L "https://api.cinara.ai/v1/generations/7c1d2e9a-4b6f-4e0a-9d2c-3f8a1b5e6c70/file" \
-H "Authorization: Bearer $CINARA_API_KEY" -o welcome.mp3Download subtitles for speech
GET /v1/generations/{id}/subtitles
Returns SRT or VTT captions for a succeeded speech or dialogue generation. Captions show the script exactly as written; sound tags aren't shown.
- Dialogue captions come from the line timings, with the speaker's name before each line.
- Speech captions are timed by listening to the audio. The first request can take a while; the result is cached.
Query parameters
| Name | Default | Description |
|---|---|---|
format | srt | srt or vtt. Any other value gives SRT. |
Response
200 OK with Content-Type: application/x-subrip; charset=utf-8 or text/vtt; charset=utf-8, and Content-Disposition: attachment; filename="cinara-speech-<first 8 characters of id>.<format>" (for dialogue too).
1
00:00:00,000 --> 00:00:01,620
Welcome to the course.
2
00:00:01,700 --> 00:00:03,480
Today we start with the basics.Errors
| Status | error | Message |
|---|---|---|
| 404 | not_found | Generation not found (not found, not speech or dialogue, or not succeeded) |
| 409 | unavailable | Subtitles are available for speech generated from now on. Generate this script again to get them. (older speech) |
| 422 | unavailable | Couldn't time subtitles for this audio |
Credits
Free.
Example
bash
curl "https://api.cinara.ai/v1/generations/7c1d2e9a-4b6f-4e0a-9d2c-3f8a1b5e6c70/subtitles?format=vtt" \
-H "Authorization: Bearer $CINARA_API_KEY" -o welcome.vttGet the current account
GET /v1/me
Returns the member the key acts as, the workspace, and its credit balance.
Response
200 OK
json
{
"user": {
"id": "9a7c3e1b-2d4f-4b6a-8e0c-5f1d3b7a9c28",
"email": null,
"name": "Alex Moreno",
"phone": "+15555550123",
"phoneVerified": true
},
"workspace": {
"id": "3f6b2a1c-8d4e-4b7a-9c2d-5e1f0a9b8c7d",
"name": "Moreno Studio",
"plan": "free",
"role": "owner"
},
"credits": 49946
}| Field | Description |
|---|---|
user | The key's creator. email is always null for API key requests. phoneVerified must be true for endpoints that create or spend. |
workspace.plan | free, starter, creator, pro, scale, business or enterprise. |
workspace.role | The creator's role in the workspace. |
credits | The workspace's credit balance. |
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/me \
-H "Authorization: Bearer $CINARA_API_KEY"