Animatra

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 '{}'