Automotion docs
Guides

AI script generation

Turn a brief — or an existing transcript — into a structured, render-ready video script with POST /v1/scripts.

Automating video means automating two things: the script and the render. POST /v1/renders handles the second; POST /v1/scripts handles the first. You send a brief plus grounding parameters — tone, audience, structure, visual style, scene and word bounds, optionally source material to transform — and get back a validated script: scenes of narration (voiceText) and image prompts, plus a title and description.

The endpoint is synchronous: the response carries the finished script, typically after tens of seconds. Behind the scenes the model is re-prompted until the draft satisfies every constraint you set, so the shape you receive is guaranteed — exactly N scenes if you asked for N, every scene within your word bounds, an imagePrompt on every scene unless you opted out.

Pricing: max(2, ceil(scenes / 4)) credits per script — a 14-scene short costs 4 credits — charged only on success. A generation that cannot produce a valid script answers LLM_FAILED and charges nothing. Your balance is checked up front, so an underfunded call fails fast with INSUFFICIENT_CREDITS before any model work happens.

From a brief

Generate a script
curl -X POST https://api.useautomotion.com/v1/scripts \
  -H "Authorization: Bearer $AUTOMOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brief": "Five stoic habits that build discipline",
    "sceneCount": 12,
    "tone": "calm, assertive",
    "audience": "young professionals",
    "structure": "hook, five numbered points each reinforced by a practical line, strong close, call to action",
    "visualStyle": "weathered marble statues, golden torchlight, deep blacks, cinematic 9:16",
    "wordsPerScene": { "min": 9, "max": 16 }
  }'

The response:

201 Created
{
  "id": "cme0x1…",
  "title": "Five Habits Stoics Used to Build Unbreakable Discipline",
  "description": "Ancient rules for a modern spine. #stoicism #discipline #shorts",
  "scenes": [
    {
      "index": 1,
      "voiceText": "Discipline is not born on hard days; it is rehearsed on easy ones.",
      "imagePrompt": "Extreme close-up of a weathered marble philosopher's face, golden torchlight cutting through darkness, cinematic 9:16.",
      "onScreenText": null
    }
  ],
  "meta": { "model": "anthropic.claude-opus-4-8", "attempts": 1, "creditsCharged": 3 },
  "createdAt": "2026-08-08T20:00:00.000Z"
}

Every grounding parameter is optional except brief. Omit sceneCount and the model chooses 10–14 scenes; omit visualStyle and image prompts get a style of the model's choosing (per-scene coherence is still enforced). The full parameter reference lives on the Scripts API page.

From existing material

Pass sourceMaterial — a transcript, article, or notes — and the model covers the same substance in entirely original wording. Sentences are never copied; the material is treated strictly as data to transform, and any instructions embedded in it are ignored.

Transform a transcript
curl -X POST https://api.useautomotion.com/v1/scripts \
  -H "Authorization: Bearer $AUTOMOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brief": "Rewrite this as an original short for my channel",
    "sourceMaterial": "…the transcript text…",
    "sceneCount": 14,
    "wordsPerScene": { "min": 9, "max": 16 }
  }'

Script → video

The script's shape maps directly onto a movie document — one scene per script scene, a voice element from voiceText, an AI-generated background from imagePrompt, duration: "voice", auto subtitles, and a cycling motion pan for the ken-burns feel:

Map scenes to a movie document
const script = await fetch("https://api.useautomotion.com/v1/scripts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOMOTION_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ brief, sceneCount: 12, visualStyle }),
}).then((r) => r.json());
 
const pans = ["left", "right", "top", "bottom", "top-left", "bottom-right"];
const movie = {
  schema: "v1",
  preset: "9:16",
  scenes: script.scenes.map((scene, i) => ({
    id: `scene-${scene.index}`,
    duration: "voice",
    elements: [
      {
        id: `bg-${scene.index}`,
        type: "image",
        generate: { prompt: scene.imagePrompt },
        width: 1080,
        height: 1920,
        motion: { pan: pans[i % pans.length] },
      },
      { id: `voice-${scene.index}`, type: "voice", text: scene.voiceText, voiceId: "Matthew", language: "en-US" },
      { id: `subs-${scene.index}`, type: "subtitles", source: "auto", mode: "word" },
    ],
  })),
};
 
const render = await fetch("https://api.useautomotion.com/v1/renders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOMOTION_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ movie }),
}).then((r) => r.json());

See the faceless short guide for the voice + subtitles recipe in detail, and POST /v1/renders for polling/webhooks.

Good to know

  • Idempotency — send an Idempotency-Key header and retries of the same request return the original script (HTTP 200) instead of generating (and charging for) a new one. Recommended: generation is a long call, and a dropped connection should not cost a second generation.
  • Fetch it laterGET /v1/scripts/{id} returns any script you generated.
  • Usage — script generations appear in GET /v1/usage under breakdown.scriptGens.
  • Model-authored texttitle and description come from the model. Review before publishing, like any generated copy.
  • MCP — connected assistants can do this whole pipeline with the generate_script tool plus create_render.

On this page