Reference
API reference
Chasca API v1: JSON over HTTPS with bearer API keys. Work that takes time (generation and edits) returns 202 with a queued record you can poll or stream.
https://app.trychasca.com/api Authentication
Every /v1 endpoint except voices and languages needs an API key, sent as
Authorization: Bearer chk_live_…. Create keys in the app under Settings → API keys.
API access starts on Plus, and API generations use plan minutes at 2x.
Conventions
- Bodies are JSON (
Content-Type: application/json). Timestamps are ISO 8601 in UTC. - Queued work answers 202; creating a copy answers 201; deleting answers 204.
-
Explainer status moves
queued → generating → rendering → ready, or ends infailedwith a readableerror.stageandprogress(0–1) describe the step in between. - Media URLs are signed and expire after about a week. Fetch the explainer again for fresh links.
Endpoints
POST /v1/explainer
Queue a new explainer. Returns 202 with the queued record.
| Field | Type | Description |
|---|---|---|
input | string | What to explain: a topic, a question, or the full text of a document (up to 200,000 characters). Alias: prompt. One of input, source or sceneGraph is required. |
length | string | number | "M:SS" (like "1:30") or seconds, a multiple of 30 up to 360. Omit for automatic. Alias: lengthSeconds. |
aspect | string | 16:9 (default), 9:16 or 1:1. |
voice | string | A narrator id such as chasca:sulafat (default) or chasca:kore. Every narrator speaks every language. See Voices. |
language | string | Narration language code, e.g. en, es-419, ja. See Languages. |
source | string | Source text to explain from (up to 400,000 characters). The script stays faithful to it. |
preset | string | Drawing style: marker (default), chalkboard, pencil, blueprint, crayon or clean. |
fillMode | string | How color washes in after each outline: A fade, B wipe, C region wash (default), D scribble. |
pace | string | relaxed, balanced (default) or brisk. |
music | boolean | Add a quiet background bed under the narration. Default false. |
sceneGraph | object | Skip the writing step and render your own scene graph (scenes with narration, heading and elements). |
curl -X POST https://app.trychasca.com/api/v1/explainer \
-H "Authorization: Bearer $CHASCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "How does compound interest snowball?",
"length": "1:30",
"aspect": "9:16",
"voice": "chasca:sulafat",
"language": "en",
"preset": "chalkboard",
"pace": "balanced"
}' {
"id": "0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60",
"status": "queued",
"stage": null,
"progress": 0,
"title": null,
"prompt": "How does compound interest snowball?",
"lengthSeconds": 90,
"voice": "chasca:sulafat",
"language": "en",
"aspect": "9:16",
"preset": "chalkboard",
"fillMode": "C",
"pace": "balanced",
"music": false,
"videoUrl": null,
"posterUrl": null,
"subtitlesUrl": null,
"durationSeconds": null,
"watermarked": false,
"sceneGraph": null,
"headVersionId": null,
"source": null,
"error": null,
"createdVia": "api",
"createdAt": "2026-09-23T09:14:02.118Z",
"updatedAt": "2026-09-23T09:14:02.118Z"
} GET /v1/explainer/:id
One explainer with everything: status, videoUrl, posterUrl, subtitlesUrl, the
editable sceneGraph, per-scene timings in scenes, and every entry in
versions.
curl https://app.trychasca.com/api/v1/explainer/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60 \
-H "Authorization: Bearer $CHASCA_API_KEY" {
"id": "0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60",
"status": "ready",
"stage": null,
"progress": 1,
"title": "How compound interest snowballs",
"lengthSeconds": 90,
"durationSeconds": 88.4,
"videoUrl": "https://app.trychasca.com/media/explainers/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/v1/video.mp4?exp=1790000000&sig=…",
"posterUrl": "https://app.trychasca.com/media/explainers/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/v1/poster.jpg?exp=1790000000&sig=…",
"subtitlesUrl": "https://app.trychasca.com/media/explainers/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/v1/subtitles.vtt?exp=1790000000&sig=…",
"sceneGraph": {
"title": "How compound interest snowballs",
"language": "en",
"scenes": [
{
"id": "s1",
"heading": "THE MONEY THAT GROWS ITSELF",
"narration": "Picture planting a tiny seed…",
"elements": [
{ "id": "seed", "type": "icon", "icon": "seedling", "label": "SEED", "revealWord": "seed" }
]
}
]
},
"scenes": [
{ "id": "s1", "index": 0, "heading": "THE MONEY THAT GROWS ITSELF", "start": 0, "duration": 19.3 }
],
"versions": [
{
"id": "5f1d…",
"number": 1,
"status": "ready",
"note": null,
"changedScenes": [],
"videoUrl": "https://app.trychasca.com/media/…",
"durationSeconds": 88.4,
"minutesCharged": 2.947,
"createdAt": "2026-09-23T09:14:02.301Z",
"readyAt": "2026-09-23T09:14:49.870Z",
"error": null
}
],
"shareUrl": null,
"error": null
} GET /v1/explainer?limit=50
Your explainers, newest first. limit is 1–100 and defaults to 50. Summaries omit the scene graph and versions.
curl "https://app.trychasca.com/api/v1/explainer?limit=20" \
-H "Authorization: Bearer $CHASCA_API_KEY" {
"explainers": [
{ "id": "0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60", "status": "ready", "title": "How compound interest snowballs", "durationSeconds": 88.4, "createdAt": "2026-09-23T09:14:02.118Z" }
]
} POST /v1/explainer/:id/edit
Edit with a plain-language { "instruction": "..." }, or send a full edited
{ "sceneGraph": { ... } }. Returns 202 with the queued version. Only the scenes
that changed are re-rendered, and the first re-render of every video is free. Wait for the version’s
status to reach ready; the explainer’s videoUrl then points at it.
curl -X POST https://app.trychasca.com/api/v1/explainer/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/edit \
-H "Authorization: Bearer $CHASCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "instruction": "In scene 3, call the two savers Ana and Ben" }' {
"id": "8a2c7e10-…",
"number": 2,
"status": "queued",
"note": "In scene 3, call the two savers Ana and Ben",
"changedScenes": [],
"videoUrl": null,
"posterUrl": null,
"durationSeconds": null,
"minutesCharged": 0,
"createdAt": "2026-09-23T09:20:11.004Z",
"readyAt": null,
"error": null
} POST /v1/explainer/:id/revert
Make an earlier, finished version current again. Body: { "versionId": "..." }. Returns the explainer.
curl -X POST https://app.trychasca.com/api/v1/explainer/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/revert \
-H "Authorization: Bearer $CHASCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "versionId": "5f1d…" }' POST /v1/explainer/:id/duplicate
Copy an explainer, scene graph and all, so you can take it somewhere new. Returns 201 with the copy.
curl -X POST https://app.trychasca.com/api/v1/explainer/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60/duplicate \
-H "Authorization: Bearer $CHASCA_API_KEY" DELETE /v1/explainer/:id
Delete an explainer. Returns 204 with no body.
curl -X DELETE https://app.trychasca.com/api/v1/explainer/0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60 \
-H "Authorization: Bearer $CHASCA_API_KEY" GET /v1/explainer/events
A Server-Sent Events
stream with an event: status frame for every status change of any of your explainers. Keep one
connection open instead of polling.
curl -N https://app.trychasca.com/api/v1/explainer/events \
-H "Authorization: Bearer $CHASCA_API_KEY" event: status
data: {"type":"status","explainerId":"0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60","status":"generating","stage":"storyboard","progress":0.3}
event: status
data: {"type":"status","explainerId":"0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60","status":"rendering","stage":"drawing","progress":0.72}
event: status
data: {"type":"status","explainerId":"0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60","status":"ready","stage":null,"progress":1} GET /v1/voices No key needed
The voice catalog. Every narrator speaks every language, so the list is the same for all of them. Each voice
has a tone, a group and a preview_url. More on the
Voices page.
curl "https://app.trychasca.com/api/v1/voices" {
"default": "chasca:sulafat",
"voices": [
{
"id": "chasca:sulafat",
"name": "Sulafat",
"description": "Warm and natural, like a favorite teacher. The all-purpose default.",
"tone": "Warm",
"group": "warm",
"language": "en",
"gender": "female",
"isDefault": true,
"multilingual": true,
"kind": "narrator",
"preview_url": "https://app.trychasca.com/api/v1/voices/chasca%3Anova/preview.mp3"
},
{
"id": "edge:es-MX-DaliaNeural",
"name": "Dalia",
"description": "Friendly, Positive. Native es-MX speaker.",
"language": "es-MX",
"gender": "female",
"isDefault": false,
"multilingual": false,
"kind": "native",
"preview_url": "https://app.trychasca.com/api/v1/voices/edge%3Aes-MX-DaliaNeural/preview.mp3"
}
]
} GET /v1/languages No key needed
Every narration language. beta languages are newer to the voice model, so narration quality can vary.
curl https://app.trychasca.com/api/v1/languages {
"languages": [
{ "code": "en", "label": "English", "native": "English", "beta": false },
{ "code": "es-419", "label": "Spanish (Latin America)", "native": "Español (Latinoamérica)", "beta": false },
{ "code": "pa", "label": "Punjabi", "native": "ਪੰਜਾਬੀ", "beta": true }
]
} GET /v1/account/state
Who the key belongs to, and how many videos they have made.
curl https://app.trychasca.com/api/v1/account/state \
-H "Authorization: Bearer $CHASCA_API_KEY" { "videosGenerated": 14, "image": null, "isAdmin": false, "name": "Ada Lovelace" } GET /v1/billing/status
The plan behind the key and where you are in the period: minutes used and remaining, overage, and entitlements. Free
accounts get videoAllowance, videosUsed and videosRemaining instead.
curl https://app.trychasca.com/api/v1/billing/status \
-H "Authorization: Bearer $CHASCA_API_KEY" {
"plan": "pro",
"planLabel": "Pro",
"billingInterval": "annual",
"status": "active",
"trialStatus": null,
"quotaMinutes": 300,
"bonusMinutes": 0,
"minutesUsedThisPeriod": 41.5,
"minutesRemaining": 258.5,
"periodStart": "2026-09-01T00:00:00.000Z",
"periodEnd": "2026-10-01T00:00:00.000Z",
"cancelAtPeriodEnd": false,
"overageEnabled": false,
"overagePerMinute": 0.33,
"pricePerMonth": 29.99,
"maxLengthSeconds": 360,
"entitlements": { "api": true, "branding": true, "voiceClone": true, "priority": false, "watermark": false, "maxLength": 360, "videoAllowance": null }
} GET /config No key needed
Public configuration for clients: where the site, app and API live.
curl https://app.trychasca.com/api/config {
"authEnforced": true,
"googleEnabled": false,
"requireEmailVerification": false,
"siteUrl": "https://trychasca.com",
"appUrl": "https://app.trychasca.com",
"apiUrl": "https://app.trychasca.com/api",
"devMail": false
} GET /health No key needed
Liveness check for load balancers and uptime monitors.
curl https://app.trychasca.com/api/health { "status": "ok", "service": "chasca-api", "time": "2026-09-23T09:14:00.000Z", "db": "postgres", "tts": "edge", "llmConfigured": true } Errors
Every error has the same shape, with a stable machine-readable code and a message you can show to people:
{
"error": true,
"code": "api_requires_plan",
"message": "API and MCP access start on the Plus plan.",
"status": 402
} | Status | Code | Meaning |
|---|---|---|
| 400 | bad_request, empty_input, bad_voice | The request is malformed or missing what to explain. |
| 401 | unauthenticated | No key, or the key is wrong or revoked. |
| 402 | api_requires_plan | API and MCP access start on Plus. |
| 402 | minutes_exhausted | No minutes left this period and overage is off. |
| 404 | not_found | No explainer with that id on your account. |
| 409 | still_rendering, no_changes | The video is mid-render, or an edit changes nothing. |
| 429 | rate_limited | Too many requests. Wait for the Retry-After header, then retry. |
| 500 | internal | Our fault. Details are logged on our side, never leaked. |
Rate limits
- Generation and edits (
POST /v1/explainer,…/edit): 20 requests per minute. - Everything else: 200 requests per minute.
-
Over the limit you get 429
rate_limitedwith aRetry-Afterheader in seconds. The SDK retries read requests once after that delay and exposes it on errors asretryAfter.