Animatra API
Generate clips, build animated stories with consistent characters, and record narrated tutorials. Every request runs inside one organization: the one the API key belongs to. Every dollar figure is what your organization is charged, in credits, so an estimate names what the work takes off your balance.
Authentication
An organization API key from Organization settings → API, sent as `Authorization: Bearer anm_…` (or as an `x-api-key` header). Each key carries scopes chosen when it is created; a call outside them returns 403 naming the scope it needs.
- clips:read
- Read clips and their status
- clips:write
- Create, retry and delete clips
- stories:read
- Read stories, characters, shots and renders
- stories:write
- Create and change stories, approve, and animate
- tutorials:read
- Read tutorial scripts and runs
- tutorials:write
- Create, change and run tutorials
- spend:read
- Read this month's spend
- webhooks:manage
- Add, change and remove webhook endpoints
curl -X GET "https://YOUR-DOMAIN/api/v1/org/current" \ -H "Authorization: Bearer anm_YOUR_KEY"
Each key has its own rate limit (120 requests per minute unless it was created with a different limit). A refused call returns 429 with a Retry-After header. Anything that would pass the organization's monthly spend ceiling returns 402.
Webhooks
Each delivery is a POST with a JSON body `{ id, event, createdAt, organizationId, data }`. Verify it with the endpoint's secret: compute HMAC-SHA256 over `<x-animatra-timestamp>.<raw body>` and compare to the `x-animatra-signature` header (`sha256=<hex>`). Deliveries retry five times with backoff; a 2xx stops them.
clip.completedgeneration.failedcharacter.readykeyframe.readyshot.animatedanimatic.readyfilm.readyshort.readytutorial.completed
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, headers, rawBody) {
const expected = "sha256=" + createHmac("sha256", secret)
.update(`${headers["x-animatra-timestamp"]}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(headers["x-animatra-signature"]));
}Clips (6)
Single text-to-video clips.
POST/generationsCreate a clip
Queues a text-to-video clip. Returns immediately; poll `GET /generations/{id}` or subscribe to `clip.completed`. Refused with 402 when the estimate would pass the organization's monthly ceiling.
Request body
- prompt *
- string
- durationSec *
- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 · default 5
- aspectRatio *
- 16:9 | 9:16 | 1:1 · default 16:9
- stylePreset
- cartoon | anime | 3d-animated | claymation | stop-motion | watercolor | storybook | pixel-art | comic | cinematic | whiteboard
- providerId
- string
Responses
- 201
- Queued
{ "id": "…", "status": "queued", "estimatedCostUsd": 0.88 }
curl -X POST "https://YOUR-DOMAIN/api/v1/generations" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/generationsList generations
Parameters
- kind
- query · clip | keyframe | final | tutorial | narration | music
- status
- query · queued | running | succeeded | failed
- q
- query · string · Matches the prompt.
- providerId
- query · string
- limit
- query · integer
- cursor
- query · string · `nextCursor` from the previous page.
Responses
- 200
- A page, newest first
{ "generations": [ { "id": "6fe04814-85c9-4eae-a9b0-36b981e1bb57", "kind": "clip", "prompt": "A paper boat drifting down a rain-streaked window, morning light", "status": "succeeded", "providerId": "fal-kling-v2.5-turbo-pro", "estimatedCostUsd": 0.88, "actualCostUsd": 0.88, "durationSec": 5, "createdAt": "2026-09-15T04:00:15.000Z", "playbackUrl": "https://…signed, valid for one hour…", "thumbnailUrl": "https://…signed…" } ], "nextCursor": null }
curl -X GET "https://YOUR-DOMAIN/api/v1/generations" \ -H "Authorization: Bearer anm_YOUR_KEY"
DELETE/generationsDelete generations
Request body
- ids *
- array
Responses
- 200
- Count removed
{ "deleted": 2 }
curl -X DELETE "https://YOUR-DOMAIN/api/v1/generations" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/generations/{id}Get a generation
Parameters
- id *
- path · string · Generation id
Responses
- 200
- The generation with playback URLs
{ "id": "6fe04814-85c9-4eae-a9b0-36b981e1bb57", "kind": "clip", "prompt": "A paper boat drifting down a rain-streaked window, morning light", "status": "succeeded", "providerId": "fal-kling-v2.5-turbo-pro", "estimatedCostUsd": 0.88, "actualCostUsd": 0.88, "durationSec": 5, "createdAt": "2026-09-15T04:00:15.000Z", "playbackUrl": "https://…signed, valid for one hour…", "thumbnailUrl": "https://…signed…" }
curl -X GET "https://YOUR-DOMAIN/api/v1/generations/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"PATCH/generations/{id}Rewrite a clip's prompt before it is made
Works while a clip is queued, running or didn't complete; a clip that is already made is answered with 409, since its prompt is the record of what was made. Follow this with `POST /generations/{id}/retry` to run it with the new words. Every other kind of generation composes its prompt from the shot, character or script it belongs to, and is answered with 409 naming where to edit it.
Parameters
- id *
- path · string · Generation id
Request body
- prompt *
- string
Responses
- 200
- The generation
curl -X PATCH "https://YOUR-DOMAIN/api/v1/generations/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/generations/{id}/retryRun a generation again
For one that didn't complete, and for one still queued or running after ten minutes, which only happens when the pipeline wasn't listening.
Parameters
- id *
- path · string · Generation id
Responses
- 200
- Queued again
{ "id": "…", "status": "queued" }
curl -X POST "https://YOUR-DOMAIN/api/v1/generations/{id}/retry" \
-H "Authorization: Bearer anm_YOUR_KEY"Stories (19)
Story bibles: premise, style guide, cast, shots, animatic and film.
POST/story-biblesStart a story
Claude expands the premise into a logline, visual style, tone, setting and palette before this returns.
Request body
- title *
- string
- premise *
- string
- stylePreset
- cartoon | anime | 3d-animated | claymation | stop-motion | watercolor | storybook | pixel-art | comic | cinematic | whiteboard
Responses
- 201
- The story bible
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/story-biblesList stories
Responses
- 200
- Stories with counts and a cover
{ "storyBibles": [] }
curl -X GET "https://YOUR-DOMAIN/api/v1/story-bibles" \ -H "Authorization: Bearer anm_YOUR_KEY"
DELETE/story-biblesDelete stories and everything inside them
Shots, keyframes, animatics and films are deleted. Characters are kept with their drawings: their `storyBibleId` becomes null, and `characters/{id}/copy` moves them into any story at no charge.
Request body
- ids *
- array
Responses
- 200
- Count removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/story-bibles" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/story-bibles/{id}Get a story with its renders
Parameters
- id *
- path · string · Story id
Responses
- 200
- Story, animatic and film URLs, share tokens
curl -X GET "https://YOUR-DOMAIN/api/v1/story-bibles/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"PATCH/story-bibles/{id}Edit title, premise, logline, style guide, palette or music level
Parameters
- id *
- path · string · Story id
Request body
- title
- string
- premise
- string · The story in your own words. Every shot list and script drafted afterwards reads it; the logline and style guide stay as they are until `story-bibles/{id}/bible` writes them again.
- logline
- string
- styleGuide
- object
- palette
- array
- musicLevel
- integer · How loud the score sits under the narration in the final film. At 0 the film is rendered with no music, which also saves composing it.
Responses
- 200
- The updated story
curl -X PATCH "https://YOUR-DOMAIN/api/v1/story-bibles/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/bibleWrite the logline, style guide and palette from the premise
For a premise edited into a different story, where the logline and style guide still describe the story the film used to be. Nothing already drawn, animated or recorded changes: the next keyframe follows the new style. `?estimate=1` returns the cost without writing anything.
Parameters
- id *
- path · string · Story id
Responses
- 200
- The updated story
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/bible" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/story-bibles/{id}/shot-listDraft a shot list with Claude
Parameters
- id *
- path · string · Story id
Request body
- shotCount *
- integer · default 6
Responses
- 202
- Drafting; shots appear within seconds
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shot-list" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/shots/keyframe-allDraw a keyframe for every draft shot, or for the selected shots
Without `shotIds`, draws every draft shot. With `shotIds`, draws each selected shot that is not being worked on, which draws again the ones that already have a keyframe; those go back to review and keep their earlier drawings in history. Add `?estimate=1` to get the count, how many are drawn again, and the cost without queuing.
Parameters
- id *
- path · string · Story id
Request body
- shotIds
- array
Responses
- 200
- Queued
{ "queued": 6, "estimatedCostUsd": 0.58 }
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shots/keyframe-all" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/shots/approve-script-allApprove the words of every shot
Approves the description and spoken lines of every shot whose script has not been approved yet, or only the shots given in `shotIds`.
Parameters
- id *
- path · string · Story id
Request body
- shotIds
- array
Responses
- 200
- Count approved
{ "approved": 6 }
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shots/approve-script-all" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/shots/approve-allApprove every keyframe waiting for review, or the selected ones
Parameters
- id *
- path · string · Story id
Request body
- shotIds
- array
Responses
- 200
- Approved
{ "approved": 4 }
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shots/approve-all" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/shots/animate-allAnimate every shot with an approved keyframe, or the selected shots
Without `shotIds`, animates every shot with an approved keyframe. With `shotIds`, animates each selected shot that is approved or already animated, which animates the latter again. Add `?estimate=1` to price it without queuing.
Parameters
- id *
- path · string · Story id
Request body
- shotIds
- array
Responses
- 200
- Queued
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shots/animate-all" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/shots/reorderReorder shots
Parameters
- id *
- path · string · Story id
Request body
- shotIds *
- array
Responses
- 200
- Reordered
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shots/reorder" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/animaticAssemble the animatic
Assembles the animatic. Shots nobody has changed are joined again from the pieces the last assembly kept, so only what has changed is built and paid for. Add `?estimate=1` to get the cost, the number of shots that would be built (`changed`) and their ids, without starting it.
Parameters
- id *
- path · string · Story id
Responses
- 202
- Assembling; `animatic.ready` follows
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/animatic" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/story-bibles/{id}/animatic/approveApprove the animatic
Parameters
- id *
- path · string · Story id
Responses
- 200
- Stage is now animatic_approved
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/animatic/approve" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/story-bibles/{id}/renderRender the final film
Renders the film, and renders a finished film again after a trim, a reorder or a change of music level. Only the shots that have changed are built; the score is used again unless `freshMusic` asks for a new one. Add `?estimate=1` to get the cost, the number of shots that would be built (`changed`) and whether the score is being used again (`musicReused`), without starting it.
Parameters
- id *
- path · string · Story id
Request body
- freshMusic
- boolean · Compose a new score instead of using the one this story already has.
Responses
- 202
- Rendering; `film.ready` follows
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/render" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/story-bibles/{id}/share/{kind}Share a render publicly
Parameters
- id *
- path · string · Story id
- kind *
- path · string · `animatic` or `film`
Responses
- 200
- A token; the page is /watch/{token}
{ "shareToken": "…" }
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/share/{kind}" \
-H "Authorization: Bearer anm_YOUR_KEY"DELETE/story-bibles/{id}/share/{kind}Stop sharing
Parameters
- id *
- path · string · Story id
- kind *
- path · string · `animatic` or `film`
Responses
- 200
- Sharing off
curl -X DELETE "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/share/{kind}" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/story-bibles/{id}/shortsCut a short from the film
A vertical (9:16, for YouTube Shorts, TikTok and Reels) or square (1:1) cut of the finished film with captions in the chosen style. ffmpeg only, so it spends nothing; `short.ready` follows and the short appears in `GET /story-bibles/{id}` under `shorts`.
Parameters
- id *
- path · string · Story id
Request body
- format *
- 9:16 | 1:1 · default 9:16
- framing *
- blur | crop · default blur
- captionStyle *
- bold | classic | clean | none · default bold
Responses
- 202
- Cutting
{ "renderId": "…", "format": "9:16" }
curl -X POST "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shorts" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'DELETE/story-bibles/{id}/shortsDelete shorts
Parameters
- id *
- path · string · Story id
Request body
- ids *
- array
Responses
- 200
- Count removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/story-bibles/{id}/shorts" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'Characters (12)
A story's cast, each with a four-angle turnaround sheet.
POST/charactersAdd a character
Claude writes the visual description, then four turnaround angles are drawn; `character.ready` follows. Send multipart form data with a `reference` file (a drawing or a photo) and both the description and every angle are drawn to look like it.
Request body
- storyBibleId *
- string
- name *
- string
- idea *
- string
Responses
- 201
- The character
curl -X POST "https://YOUR-DOMAIN/api/v1/characters" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/charactersList characters
Without `storyBibleId`, lists every character in the organization, including characters whose story was deleted (`storyBibleId` is null).
Parameters
- storyBibleId
- query · string
Responses
- 200
- Characters with turnaround image URLs
curl -X GET "https://YOUR-DOMAIN/api/v1/characters" \ -H "Authorization: Bearer anm_YOUR_KEY"
DELETE/charactersDelete characters
Request body
- ids *
- array
Responses
- 200
- Count removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/characters" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'PATCH/characters/{id}Rename, change the voice or the description
Parameters
- id *
- path · string · Character id
Request body
- name
- string
- voiceId
- string,null
- description
- string
Responses
- 200
- The character
curl -X PATCH "https://YOUR-DOMAIN/api/v1/characters/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'PUT/characters/{id}/referenceAdd or replace the reference image
The turnaround is redrawn from the new image only when you call `regenerate-refs` afterwards.
Parameters
- id *
- path · string · Character id
Request body (multipart form)
- reference *
- string · A drawing or a photo of the character: PNG, JPEG or WebP, up to 8 MB.
Responses
- 200
- The character
curl -X PUT "https://YOUR-DOMAIN/api/v1/characters/{id}/reference" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-F "[email protected]"DELETE/characters/{id}/referenceRemove the reference image
Parameters
- id *
- path · string · Character id
Responses
- 200
- The character
curl -X DELETE "https://YOUR-DOMAIN/api/v1/characters/{id}/reference" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/characters/{id}/approveApprove the turnaround
Parameters
- id *
- path · string · Character id
Responses
- 200
- Approved
curl -X POST "https://YOUR-DOMAIN/api/v1/characters/{id}/approve" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/characters/{id}/regenerate-refsRedraw the turnaround
Refused with `character_not_in_story` for a character whose story was deleted, because the drawing follows a story's style guide. Bring the character into a story first.
Parameters
- id *
- path · string · Character id
Responses
- 200
- Drawing again
curl -X POST "https://YOUR-DOMAIN/api/v1/characters/{id}/regenerate-refs" \
-H "Authorization: Bearer anm_YOUR_KEY"GET/characters/{id}/ref-setsKept sets of drawings
The sets of angles kept for the character, newest first: the one in use and up to two earlier ones. A drawing waiting for a safety review has no links.
Parameters
- id *
- path · string · Character id
Responses
- 200
- Sets, each with its angles
curl -X GET "https://YOUR-DOMAIN/api/v1/characters/{id}/ref-sets" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/characters/{id}/ref-sets/usePut an earlier set of drawings back in use
Pass the `generationIds` of a complete set from `ref-sets`. The character goes back to review, and keyframes already drawn stay as they are. Refused while the character is being drawn or while a drawing in the set waits for a safety review.
Parameters
- id *
- path · string · Character id
Request body
- generationIds *
- array
Responses
- 200
- The character
curl -X POST "https://YOUR-DOMAIN/api/v1/characters/{id}/ref-sets/use" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/characters/{id}/copyBring this character into another story
Copies the character, the angles already drawn for them and any reference image into the story you name, so the same person can appear in several films. A character whose story was deleted (`storyBibleId` is null) is moved into the story instead of copied, and the answer is 200 rather than 201. Nothing is drawn again and nothing is charged.
Parameters
- id *
- path · string · Character id
Request body
- storyBibleId *
- string
Responses
- 200
- The character, moved into the story
- 201
- The character in its new story
curl -X POST "https://YOUR-DOMAIN/api/v1/characters/{id}/copy" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/characters/{id}/reviseChange the description in your own words
Say what should change about the character and the description is rewritten to match, leaving the rest of it alone. Every angle and every keyframe is drawn from that description, so call `regenerate-refs` afterwards to draw the turnaround again.
Parameters
- id *
- path · string · Character id
Request body
- changes *
- string
Responses
- 200
- The character, with the new description
curl -X POST "https://YOUR-DOMAIN/api/v1/characters/{id}/revise" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'Shots (19)
A story's shots: keyframe first, then animation.
POST/shotsAdd a shot
`index` is the position the shot takes, counted from 0; the shots from there on move down one. An index past the end puts it last.
Request body
- storyBibleId *
- string
- index *
- integer
- prompt *
- string
- durationSec *
- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 · default 5
- characterIds *
- array · default
- narrationLines *
- array · default
- cameraMotion *
- string | null · default null
- lipSync *
- boolean · default false
Responses
- 201
- The shot
curl -X POST "https://YOUR-DOMAIN/api/v1/shots" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/shotsList shots
Parameters
- storyBibleId
- query · string
Responses
- 200
- Shots in story order with keyframe and video URLs
curl -X GET "https://YOUR-DOMAIN/api/v1/shots" \ -H "Authorization: Bearer anm_YOUR_KEY"
DELETE/shotsDelete shots
Request body
- ids *
- array
Responses
- 200
- Count removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/shots" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'PATCH/shots/{id}Edit prompt, length, cast, narration, camera, model or lip-sync
Parameters
- id *
- path · string · Shot id
Request body
- prompt
- string
- durationSec
- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
- characterIds
- array
- narrationLines
- array
- cameraMotion
- string | null · A camera-motion preset; null lets the model choose.
- videoProviderId
- string,null · The video model to animate this shot with; null picks the cheapest that takes the shot's length.
- lipSync
- boolean · Redraw the speaker's mouth to match the narration when the film renders.
- trimStartMs
- integer · Milliseconds cut from the start of this shot's clip.
- trimEndMs
- integer | null · The millisecond the shot stops at, or null to run to the end of its clip. Both are held inside the clip's own length, keeping at least one second.
Responses
- 200
- The shot
curl -X PATCH "https://YOUR-DOMAIN/api/v1/shots/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/shots/{id}/approve-scriptApprove a shot's words
Marks this shot's description and spoken lines as read and approved, as they stand right now. A shot cannot be animated until this is set, and editing either the description or a line takes it back.
Parameters
- id *
- path · string · Shot id
Responses
- 200
- The shot
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/approve-script" \
-H "Authorization: Bearer anm_YOUR_KEY"DELETE/shots/{id}/approve-scriptTake back a shot's approval
Parameters
- id *
- path · string · Shot id
Responses
- 200
- The shot
curl -X DELETE "https://YOUR-DOMAIN/api/v1/shots/{id}/approve-script" \
-H "Authorization: Bearer anm_YOUR_KEY"GET/shots/{id}/linesA shot's lines and their recordings
Each spoken line with a link to its recording, or null where those words in that voice have never been spoken.
Parameters
- id *
- path · string · Shot id
Responses
- 200
- The lines
{ "lines": [ { "characterId": "…", "text": "Hello!", "url": "https://…", "own": false } ] }
curl -X GET "https://YOUR-DOMAIN/api/v1/shots/{id}/lines" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/lines/{index}/recordingKeep your own recording of one line
Uploads a recording of this line in somebody's own voice as multipart form data, in the field `recording` (MP3, M4A, WAV, WebM or OGG, up to 10 MB). It is used wherever that line is spoken, whatever voice the character has, until the words themselves change.
Parameters
- id *
- path · string · Shot id
- index *
- path · string · Which line of the shot, counting from zero
Responses
- 200
- The recording
{ "url": "https://…", "own": true }
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/lines/{index}/recording" \
-H "Authorization: Bearer anm_YOUR_KEY"DELETE/shots/{id}/lines/{index}/recordingRemove your own recording of one line
The character's own voice speaks the line again from the next assembly.
Parameters
- id *
- path · string · Shot id
- index *
- path · string · Which line of the shot, counting from zero
Responses
- 200
- How many recordings were removed
{ "removed": 1 }
curl -X DELETE "https://YOUR-DOMAIN/api/v1/shots/{id}/lines/{index}/recording" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/lines/draftWrite a shot's lines with Claude
Writes what the people in this shot say, from the shot's description and the story around it. Replaces the lines the shot has, and takes back its script approval. Add `?estimate=1` to price it without writing anything.
Parameters
- id *
- path · string · Shot id
Responses
- 200
- The shot, with its new lines
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/lines/draft" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/lines/speakRecord a shot's lines
Records the shot's lines so they can be heard before anything is drawn or animated. The animatic and the film reuse these same recordings, so a line is never paid for twice. Add `?estimate=1` to price it without recording.
Parameters
- id *
- path · string · Shot id
Responses
- 202
- Recording
{ "id": "…", "estimatedCostUsd": 0.01 }
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/lines/speak" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/keyframe/changeChange one thing about a shot's picture
Draws the shot's picture again starting from the one it has, keeping the characters, poses, framing, colours and background, and changing only what `change` asks for. One picture's cost, and the shot goes back to review. Add `?estimate=1` to price it without drawing.
Parameters
- id *
- path · string · Shot id
Request body
- change *
- string · What should change, in your own words
Responses
- 202
- Drawing
{ "id": "…", "estimatedCostUsd": 0.1 }
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/keyframe/change" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/shots/{id}/end-keyframeDraw the picture a shot ends on
Draws the frame the animation arrives at, continuing from the shot's keyframe (one image's cost). Add `?estimate=1` to get the cost without drawing.
Parameters
- id *
- path · string · Shot id
Responses
- 202
- Drawing
{ "id": "…", "estimatedCostUsd": 0.1 }
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/end-keyframe" \
-H "Authorization: Bearer anm_YOUR_KEY"DELETE/shots/{id}/end-keyframeForget the picture a shot ends on
Parameters
- id *
- path · string · Shot id
Responses
- 200
- The shot
curl -X DELETE "https://YOUR-DOMAIN/api/v1/shots/{id}/end-keyframe" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/keyframeDraw the keyframe
Draws one keyframe, or two or four candidates to choose between with `POST /shots/{id}/keyframe/use`. A shot that already has a keyframe or a video can be drawn again: it goes back to review and keeps what it had in history. Add `?estimate=1` to get the cost without drawing.
Parameters
- id *
- path · string · Shot id
Request body
- count
- 1 | 2 | 4
Responses
- 200
- Queued
{ "id": "…", "status": "keyframe_queued", "count": 4, "estimatedCostUsd": 0.4 }
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/keyframe" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/shots/{id}/approve-keyframeApprove the keyframe
Parameters
- id *
- path · string · Shot id
Responses
- 200
- Approved
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/approve-keyframe" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/animateAnimate the approved keyframe
An already animated shot can be animated again; the earlier video stays in its history. Add `?estimate=1` to get the cost without animating.
Parameters
- id *
- path · string · Shot id
Responses
- 200
- Queued
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/animate" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/shots/{id}/keyframe/usePin an earlier keyframe from history
Parameters
- id *
- path · string · Shot id
Request body
- generationId *
- string
Responses
- 200
- The shot
curl -X POST "https://YOUR-DOMAIN/api/v1/shots/{id}/keyframe/use" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/generations/historyA shot's or character's generation history
Parameters
- shotId
- query · string
- characterId
- query · string
Responses
- 200
- Generations, newest first, each with its assets
curl -X GET "https://YOUR-DOMAIN/api/v1/generations/history" \ -H "Authorization: Bearer anm_YOUR_KEY"
Tutorials (7)
Narrated screen recordings of a real website.
POST/tutorial-scriptsCreate a tutorial script
Request body
- title *
- string
- targetUrl *
- string
- steps *
- array
- voiceId
- string
Responses
- 201
- The script
curl -X POST "https://YOUR-DOMAIN/api/v1/tutorial-scripts" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/tutorial-scriptsList scripts
Responses
- 200
- Scripts
curl -X GET "https://YOUR-DOMAIN/api/v1/tutorial-scripts" \ -H "Authorization: Bearer anm_YOUR_KEY"
DELETE/tutorial-scriptsDelete scripts
Request body
- ids *
- array
Responses
- 200
- Count removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/tutorial-scripts" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'POST/tutorial-scripts/draftDraft steps from an outline with Claude
Request body
- targetUrl *
- string
- outline *
- string
- title
- string
Responses
- 200
- A title and steps to edit before saving
curl -X POST "https://YOUR-DOMAIN/api/v1/tutorial-scripts/draft" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'GET/tutorial-scripts/{id}Get a script
Parameters
- id *
- path · string · Script id
Responses
- 200
- The script
curl -X GET "https://YOUR-DOMAIN/api/v1/tutorial-scripts/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"PATCH/tutorial-scripts/{id}Edit a script
Parameters
- id *
- path · string · Script id
Responses
- 200
- The script
curl -X PATCH "https://YOUR-DOMAIN/api/v1/tutorial-scripts/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/tutorial-scripts/{id}/runRecord the tutorial
Parameters
- id *
- path · string · Script id
Responses
- 201
- Queued; `tutorial.completed` follows
{ "id": "…", "status": "queued", "estimatedCostUsd": 0.1 }
curl -X POST "https://YOUR-DOMAIN/api/v1/tutorial-scripts/{id}/run" \
-H "Authorization: Bearer anm_YOUR_KEY"Spend (4)
What the organization has spent this month.
GET/spendThis month's spend and ceiling
Responses
- 200
- Totals, in credits
{ "monthKey": "2026-09", "spentThisMonthUsd": 12.4, "ceilingUsd": 50 }
curl -X GET "https://YOUR-DOMAIN/api/v1/spend" \ -H "Authorization: Bearer anm_YOUR_KEY"
GET/spend/breakdownBy kind and six-month trend
Responses
- 200
- Breakdown
curl -X GET "https://YOUR-DOMAIN/api/v1/spend/breakdown" \ -H "Authorization: Bearer anm_YOUR_KEY"
GET/spend/by-providerBy provider, this month
Responses
- 200
- Breakdown
curl -X GET "https://YOUR-DOMAIN/api/v1/spend/by-provider" \ -H "Authorization: Bearer anm_YOUR_KEY"
GET/spend/by-storyBy story, all time
Responses
- 200
- Breakdown
curl -X GET "https://YOUR-DOMAIN/api/v1/spend/by-story" \ -H "Authorization: Bearer anm_YOUR_KEY"
Webhooks (7)
Endpoints that receive events as they happen.
GET/webhooksList endpoints
Responses
- 200
- Endpoints and the event names
curl -X GET "https://YOUR-DOMAIN/api/v1/webhooks" \ -H "Authorization: Bearer anm_YOUR_KEY"
POST/webhooksAdd an endpoint
The signing secret is returned once in this response and never again.
Request body
- url *
- string
- description
- string
- events *
- array
- active
- boolean
Responses
- 201
- The endpoint with its secret
curl -X POST "https://YOUR-DOMAIN/api/v1/webhooks" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'PATCH/webhooks/{id}Edit an endpoint
Parameters
- id *
- path · string · Endpoint id
Responses
- 200
- The endpoint
curl -X PATCH "https://YOUR-DOMAIN/api/v1/webhooks/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"DELETE/webhooks/{id}Remove an endpoint
Parameters
- id *
- path · string · Endpoint id
Responses
- 200
- Removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/webhooks/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/webhooks/{id}/testSend a test.ping
Parameters
- id *
- path · string · Endpoint id
Responses
- 202
- Queued
curl -X POST "https://YOUR-DOMAIN/api/v1/webhooks/{id}/test" \
-H "Authorization: Bearer anm_YOUR_KEY"GET/webhooks/{id}/deliveriesRecent deliveries
Parameters
- id *
- path · string · Endpoint id
Responses
- 200
- Up to 50 deliveries, newest first
curl -X GET "https://YOUR-DOMAIN/api/v1/webhooks/{id}/deliveries" \
-H "Authorization: Bearer anm_YOUR_KEY"POST/webhooks/deliveries/{id}/redeliverDeliver again
Parameters
- id *
- path · string · Delivery id
Responses
- 202
- Queued
curl -X POST "https://YOUR-DOMAIN/api/v1/webhooks/deliveries/{id}/redeliver" \
-H "Authorization: Bearer anm_YOUR_KEY"Reference (6)
Providers, voices, the organization.
GET/providersProviders, what each charges you, and 30-day health
Responses
- 200
- Catalog
curl -X GET "https://YOUR-DOMAIN/api/v1/providers" \ -H "Authorization: Bearer anm_YOUR_KEY"
GET/voicesNarration voices with preview clips
The organization's own cloned voices come first (`own: true`), then the library. `cloning.available` says whether a new voice can be cloned on the account behind the studio.
Responses
- 200
- Voices
curl -X GET "https://YOUR-DOMAIN/api/v1/voices" \ -H "Authorization: Bearer anm_YOUR_KEY"
POST/voicesClone a voice from a recording
One to three recordings of the same person (MP3, M4A, WAV, WebM or OGG, up to 10 MB each; one to three minutes of clear speech works best). The speaker's consent is required. The voice id returned is what characters and tutorial scripts take as `voiceId`.
Request body (multipart form)
- name *
- string · Up to 60 characters.
- consent *
- true · Confirms this is your own voice or that the speaker agreed.
- samples *
- string · A recording.
Responses
- 201
- The cloned voice
curl -X POST "https://YOUR-DOMAIN/api/v1/voices" \ -H "Authorization: Bearer anm_YOUR_KEY" \ -F "name=…" \ -F "consent=…" \ -F "[email protected]"
DELETE/voices/{id}Remove a cloned voice
Characters and tutorial scripts that used it go back to the default voice.
Parameters
- id *
- path · string · Voice id
Responses
- 200
- Removed
curl -X DELETE "https://YOUR-DOMAIN/api/v1/voices/{id}" \
-H "Authorization: Bearer anm_YOUR_KEY"GET/org/currentThe organization this key belongs to, and its permissions
Responses
- 200
- Organization
curl -X GET "https://YOUR-DOMAIN/api/v1/org/current" \ -H "Authorization: Bearer anm_YOUR_KEY"
GET/notificationsIn-app notifications
Responses
- 200
- Notifications and the unread count
curl -X GET "https://YOUR-DOMAIN/api/v1/notifications" \ -H "Authorization: Bearer anm_YOUR_KEY"
Writing (1)
Redrafting the words a film is made from.
POST/redraftRedraft a piece of writing
Rewrites a character description, a premise, a logline, a shot, a clip prompt or a line of narration, keeping what it says and changing only how well it is written. `kind` names which of those it is; `context` is anything that keeps the redraft true to the film it belongs to.
Request body
- kind *
- string
- text *
- string
- context
- string
Responses
- 200
- The redrafted text, and what the call cost
curl -X POST "https://YOUR-DOMAIN/api/v1/redraft" \
-H "Authorization: Bearer anm_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'