Get started

Quickstart

Four steps from nothing to a finished MP4. Steps 1 and 2 are one-time setup on the website; after that, every video is a single API call.

1. Get an API key

Open Settings → API keys, create a key and copy it. It starts with chalk_live_sk_v1_ and is shown only once. Put it in your environment:

.env
MANIMOTION_API_KEY=chalk_live_sk_v1_...   # used by the SDKs
MANIMOTION_KEY=chalk_live_sk_v1_...       # used by the HTTP examples below
MANIMOTION_API=https://api.manimotion.dev

2. Connect storage

Videos are uploaded to your own bucket, so you own the files and serve them from your CDN. In Settings → Storage, add a Cloudflare R2, AWS S3 or MinIO bucket. Once it’s saved, every request uses it automatically and you never send bucket credentials again.

Prefer not to save credentials? You can pass them per request instead. Storage shows how.

3. Pick a model (optional)

Skip this and your videos use a good default model. To choose one, pass model with any id your plan includes. To use any model on any plan, connect your own provider key in Settings → AI providers. Details are in Models and Bring your own key.

4. Make a video with an SDK

The quickest way. generate() starts the job, waits while it runs, and returns the finished video. Most videos take 1–5 minutes.

generate.mjs
// npm install @manimotion/sdk
import { Manimotion } from "@manimotion/sdk";

const manimotion = new Manimotion(); // reads MANIMOTION_API_KEY

const video = await manimotion.videos.generate({
  prompt: "Explain how binary search works",
  onProgress: (v) => console.log(v.message),
});

console.log(video.videoUrl);
RESPONSEoutput
Planning the lesson…
Generating narration…
Designing visuals…
https://cdn.example.com/videos/a1b2c3d4.mp4

4. Or make a video over HTTP

Using another language, or want to see what the SDK does under the hood? It’s two requests.

Create a job

The response comes back immediately with a job_id. It is not the video yet.

create.sh
curl -sS -X POST "$MANIMOTION_API/video/request" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $MANIMOTION_KEY" \
  -d '{
    "prompt": "Explain Bayes theorem with a medical testing example",
    "style": "auto"
  }'
RESPONSEresponse.json
{
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "queued",
  "cached": false,
  "video_url": null,
  "eta_seconds": 150,
  "eta_display": "~2–3 min",
  "message": "Queued…",
  "tier": "tier2",
  "model": "anthropic/claude-haiku-5.5",
  "key_source": "platform"
}

Check its status

Call this every 2–3 seconds until status is completed (use video_url) or failed (read error and error_code).

status.sh
curl -sS "$MANIMOTION_API/video/status/$JOB_ID" \
  -H "x-api-key: $MANIMOTION_KEY"
RESPONSEresponse.json
{
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "video_url": "https://cdn.example.com/videos/a1b2c3d4.mp4",
  "error": null,
  "error_code": null,
  "model": "anthropic/claude-haiku-5.5",
  "key_source": "platform",
  "cached": false,
  "style": "math",
  "duration": 54.2,
  "phase": "completed",
  "message": "Done!",
  "eta_seconds": 0,
  "tier": "tier2"
}

All together

A complete script that creates a video and waits for it:

generate.sh
JOB=$(curl -sS -X POST "$MANIMOTION_API/video/request" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $MANIMOTION_KEY" \
  -d '{"prompt": "Teach the product rule with a visual derivation"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")

echo "job=$JOB"
while true; do
  BODY=$(curl -sS "$MANIMOTION_API/video/status/$JOB" -H "x-api-key: $MANIMOTION_KEY")
  echo "$BODY"
  echo "$BODY" | grep -q '"status":"completed"' && break
  echo "$BODY" | grep -q '"status":"failed"' && exit 1
  sleep 3
done
RESPONSEoutput
https://cdn.example.com/videos/a1b2c3d4.mp4

Next steps