Tools
CLI and SDK
Two thin, typed layers over the API. The SDK for code that makes videos; the chasca CLI for your terminal, scripts and CI.
https://app.trychasca.com/api Configure
Both read the same two environment variables:
export CHASCA_API_URL=https://app.trychasca.com/api
export CHASCA_API_KEY=chk_live_... CHASCA_API_URL is the API address, https://app.trychasca.com/api. Keys come from the app under
Settings → API keys (Plus and above).
The chasca CLI
# list voices (no key needed)
chasca voices
# create a 30-second vertical video and wait for it
chasca generate "How does a heat pump work?" --length 0:30 --aspect 9:16 --wait
# check on a video
chasca status 0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60
# edit it in plain language and wait for the new version
chasca edit 0b9c6f2e-5d1a-4c3e-9a47-2f8e1c7d4b60 "make the title scene shorter" --wait
# your latest videos
chasca list --limit 20 --lengthtakesM:SSin 30-second steps up to6:00.--aspectis16:9,9:16or1:1.--waitkeeps the command running until the video (or the new version) is ready.--jsonprints the raw API response, handy for piping intojq.
Working in the Chasca repository itself, run the CLI straight from source with Bun:
# from the root of the chasca-ai repository
bun packages/cli/src/index.ts voices
bun packages/cli/src/index.ts generate "Why do we have seasons?" --length 1:00 --wait --json The TypeScript SDK
@chasca/sdk runs anywhere fetch exists (Bun, Node 20+). Every response is validated
against the same contracts the API uses, and failures throw a single ChascaError type with a stable
code. Your key is kept private and never appears in error messages.
import { ChascaClient, ChascaError } from '@chasca/sdk';
const chasca = new ChascaClient({
apiKey: process.env.CHASCA_API_KEY!,
baseUrl: process.env.CHASCA_API_URL ?? 'https://app.trychasca.com/api',
});
// 1. queue a video (202) and wait until it is ready
const job = await chasca.createExplainer({
input: 'How vaccines train the immune system',
length: '1:30',
aspect: '16:9',
preset: 'chalkboard',
});
const video = await chasca.waitForExplainer(job.id, {
onUpdate: (e) => console.log(e.status, e.stage, Math.round(e.progress * 100) + '%'),
});
console.log(video.videoUrl);
// 2. edit in plain language; only the affected scenes re-render
const version = await chasca.editExplainer(video.id, 'Use a castle and guards as the analogy in scene 2');
const updated = await chasca.waitForVersion(video.id, version.id);
console.log(updated.videoUrl);
// 3. errors are typed
try {
await chasca.getExplainer('not-a-real-id');
} catch (err) {
if (err instanceof ChascaError) console.error(err.status, err.code, err.message);
} You can also edit the scene graph yourself and commit it as a new version:
// edit the scene graph directly: rename a heading, then commit it as a new version
const current = await chasca.getExplainer(video.id);
const graph = structuredClone(current.sceneGraph!);
graph.scenes[0]!.heading = 'THE SNOWBALL EFFECT';
const v3 = await chasca.editExplainerGraph(video.id, graph);
await chasca.waitForVersion(video.id, v3.id); Methods
| Method | What it does |
|---|---|
createExplainer(params) | POST /v1/explainer. Queues a video; returns the queued record. |
waitForExplainer(id, options?) | Polls until ready (resolves) or failed (throws). Options: intervalMs, timeoutMs, onUpdate. |
getExplainer(id) | GET /v1/explainer/:id with the scene graph, scenes and versions. |
listExplainers({ limit }) | GET /v1/explainer, newest first (limit 1–100). |
editExplainer(id, instruction) | POST …/edit with a plain-language instruction; returns the queued version. |
editExplainerGraph(id, sceneGraph) | POST …/edit with an edited scene graph; returns the queued version. |
waitForVersion(id, versionId, options?) | Polls until that version is ready; resolves with the updated explainer. |
revertExplainer(id, versionId) | POST …/revert. Makes an earlier finished version current. |
duplicateExplainer(id) | POST …/duplicate. Returns the copy. |
deleteExplainer(id) | DELETE /v1/explainer/:id. |
listVoices({ language }) | GET /v1/voices. Every narrator, each with a preview. |
listLanguages() | GET /v1/languages. |
The constructor is new ChascaClient({ apiKey, baseUrl }). All methods accept an optional
{ signal } so you can cancel with an AbortController.