
Make faceless AI short videos from a story idea: script, voiceover, captions, scenes.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Optional. Leave empty to sign in with OAuth. Or send your StoryShort API key as 'Bearer sk_live_...' (create one at https://storyshort.app/en/developers).
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Cancel a video that has NOT started rendering: a draft, a video still queued (PENDING), or one whose failed render is waiting for an automatic retry. The video ends as FAILED "Cancelled" and is never rendered. Credits are charged only after a render succeeds, so normally nothing had been charged; if the ledger holds a charge for it, exactly that is refunded (idempotent, never twice) and refundedCredits says how much. A video that is already rendering, finished, or a clip made straight from a prompt is refused (CANNOT_CANCEL_STARTED) and left untouched. Requires the "video:create" scope.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http storyshort https://storyshort.app/api/mcp
Headers
Authorization (optional, not in the config above): Optional. Leave empty to sign in with OAuth. Or send your StoryShort API key as 'Bearer sk_live_...' (create one at https://storyshort.app/en/developers).Cancel a video that has NOT started rendering: a draft, a video still queued (PENDING), or one whose failed render is waiting for an automatic retry. The video ends as FAILED "Cancelled" and is never rendered. Credits are charged only after a render succeeds, so normally nothing had been charged; if the ledger holds a charge for it, exactly that is refunded (idempotent, never twice) and refundedCredits says how much. A video that is already rendering, finished, or a clip made straight from a prompt is refused (CANNOT_CANCEL_STARTED) and left untouched. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| videoId* | string |
{
"type": "object",
"required": [
"videoId"
],
"properties": {
"videoId": {
"type": "string"
}
},
"additionalProperties": false
}Make the episode: 3-8 shots, 30-60 seconds, the same fictional character in every shot, narrated with captions. CHARGES credits (up to 325 credits for a default 30-second episode; longer ones (up to 60 seconds) cost more). ALWAYS call quote_character_episode first and tell the human the price: the human, not the agent, decides to spend. This tool refuses unless confirm is true, expectedCredits equals the price computed now (a changed price answers 409 PRICE_CHANGED and charges nothing) and idempotencyKey is set; StoryShort has no daily spending cap per key, so these are the guard. The series must have a REVIEWED, CONFIRMED season plan and the episode must be one of its episodes exactly as planned (SEASON_PLAN_REQUIRED / SEASON_NOT_REVIEWED / EPISODE_NOT_IN_PLAN otherwise, with a nextAction, nothing charged); the narrator voice, language, style, look and outfit come from the plan. Credits are held when it starts. A shot that cannot be animated keeps a still image and its clip credits go back; if too few shots move, or anything else fails, everything goes back. Characters are fictional adults (or animals / mascots), AI-generated: no real or famous people, no children or anyone who looks under 18, no sexual content, no logos or protected characters (refused with CONTENT_POLICY, nothing charged). Everything made here is AI-generated and labelled as such. Takes about 10-25 minutes: poll get_video with arguments { id: <the returned id / videoId> }; it reports status, stage and, when COMPLETED, videoUrl. One episode at a time per account. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| shots | array | The shots of the planned episode. Give `shots` OR `script`. |
| title | string | Optional title. |
| script | string | The narration, about 74-147 words. The system splits it into shots by sentence. Give `script` OR `shots`, exactly as planned (get_season_plan). |
| confirm* | boolean | Must be true: making an episode spends credits, and the human has seen the price. |
| sheetId | string | Omit it: the character sheet is the one the season plan names for this episode. If given it must equal that sheet. |
| language | string | Omit it: the narration language is the season plan's. If given it must equal the plan's. |
| seriesId* | string | A series id from list_series whose season plan is reviewed and confirmed. |
| shotCount | integer | With `script`: how many shots to split it into. Omit for an automatic count. |
| idempotencyKey* | string | Required. One new unique key per purchase; a repeat with the same key returns the first answer (replayed: true) and charges nothing. |
| expectedCredits* | integer | The credits the quote showed the human. Must match the price computed now. |
Make a character sheet for one of your series: 4-6 AI images (default 5: front portrait, full body, side, expressions) of ONE fictional character, from a text description. CHARGES credits: 23 credits for 5 images of a person, 11 for an animal or mascot. ALWAYS call get_character_sheet first and tell the human the price: the human, not the agent, decides to spend. This tool refuses unless confirm is true, expectedCredits equals the price computed now (a changed price answers 409 PRICE_CHANGED and charges nothing) and idempotencyKey is set; StoryShort has no daily spending cap per key, so these are the guard. Credits are taken when it starts and returned in full if no sheet comes back. If a non-primary view could not be made in time, the sheet still comes back with the images that exist (the answer says partial: true and lists missingViews) and only those images are charged: the difference is returned and creditsCharged shows what was kept. For a person the face is carried from the front portrait into the other views; the outfit follows the description and can drift a little. For an animal or mascot the views share one description and seed, so they look alike but are not guaranteed to be identical. Usually under a minute; the answer already contains the images (a slow image model fails the call and returns the credits). Characters are fictional adults (or animals / mascots), AI-generated: no real or famous people, no children or anyone who looks under 18, no sexual content, no logos or protected characters (refused with CONTENT_POLICY, nothing charged). Everything made here is AI-generated and labelled as such. A series can hold 3 sheets in total; the first sheet is chosen automatically. A series made with create_series has no saved character description: pass `description`. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| confirm* | boolean | Must be true: making a sheet spends credits, and the human has seen the price. |
| seriesId* | string | A series id from list_series. |
Create a series: StoryShort makes a video on this niche every scheduleIntervalDays, and can auto-post it to YouTube. The series NAME is the topic every video is written from, so put the user's own subject in it. Creating or changing a series is FREE. While active, the scheduler makes one video every scheduleIntervalDays (the first at its next run, within about 30 minutes) and charges each video like any video, 40 credits with the default render, at render time. It needs at least 40 credits in the balance: when the balance cannot pay for the next video the scheduler PAUSES the series (it never overdraws), so create_series and resume_series refuse with SERIES_NEEDS_CREDITS instead of making a series that would never run. Agents may keep at most 5 series active at once (SERIES_LIMIT_REACHED). StoryShort has no per-key daily spending cap: pause_series is the brake. Set startPaused: true to create it without generating (then resume_series). Accounts with fewer credits than one video (every new account starts at 0, and free accounts cannot run a series) are refused: you get SERIES_NEEDS_CREDITS with a topUpUrl, nothing is created. autoPostYouTube only works once YouTube is connected (get_connection_status) — nothing checks it here; madeForKids is the COPPA answer, ask the user. A name that already exists returns SERIES_EXISTS. TikTok auto-post is not available for series (use publish_video, which sends to Drafts). Pass idempotencyKey so a retry never makes a second series. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| name* | string | The series topic/name; every video is generated from it. |
| niche* | string | Content niche (list_niches). |
| quality | string | |
| language | string |
Create (enqueue) a new AI faceless video from a topic. Returns immediately with a video id and status "PENDING"; the render runs asynchronously — poll get_video every 20-30 seconds until status is "COMPLETED" (playable videoUrl) or "FAILED". Costs 40 credits with the default voice (+25 for a language only ElevenLabs speaks, e.g. Persian); art style does not change the price. A short balance is refused up front with 402 INSUFFICIENT_CREDITS stating credits needed, available and a top-up URL. Requires the "video:create" scope on the API key. OPTIONAL AI MOTION: pass motion_scenes (0-3, default 0 = a normal video) to turn that many scenes, starting with the first, into a 5-second AI video clip instead of a still image. Price: 40 credits per motion scene EXTRA (so 1 scene = 80 credits in total with the default voice). Call quote_video first and tell the user the price before creating. FREE plans cannot use it (403 MOTION_PLAN_REQUIRED, nothing charged). Trial accounts (no payment yet) get 1 AI clip in total (MOTION_TRIAL_LIMIT after that); a payment unlocks the rest. A clip that cannot be made falls back to the still image and its 40 credits are refunded. Content is checked first: children, real people, sexual content, protected characters and lip-sync/deepfakes are refused (422 PROMPT_BLOCKED, nothing charged).
| Argument | Type | Description |
|---|---|---|
| niche | string | Optional content niche. Call list_niches for the authoritative list with labels. |
| topic* | string | What the video is about. The full script is AI-generated from this. e.g. "3 tiny habits that quietly change your life". |
| artStyle | string | Optional visual art style. Defaults to AUTOSHORTS (cinematic). Call list_niches for the full list. |
| duration | number |
Write a video's script and scenes WITHOUT rendering or charging, so the user can read and change it first. Returns draftId, the scenes (narration + visual prompt each) and the exact render price. Free, but it runs the script writer once: needs a balance that can pay for a render and is limited to 20 drafts per hour. Then: show it → update_draft / revise_scene → render_draft only after the user approves the price. Use create_video instead when no review is wanted. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| title | string | Optional title (defaults to the topic). |
| topic* | string | What the video is about; the script is written from it. |
| artStyle | string | Optional art style (default AUTOSHORTS). |
| duration | number | Target length in seconds (default 30; 90 needs a paid plan). |
| language | string | Optional BCP-47 narration language, e.g. "en", "vi". |
{
"type": "object",
"required": [
"topic"
],
"properties": {
"title": {
"type": "string",
"maxLength": 100,
"description": "Optional title (defaults to the topic)."
},
"topic": {
"type": "string",
"maxLength": 500,
"description": "What the video is about; the script is written from it."
},
"artStyle": {
"enum": [
"AUTOSHORTS",
"LEGO",
"COMIC_BOOK",
"DISNEY_TOON",
"STUDIO_GHIBLI",
"PIXEL_ART",
"WATERCOLOR",
"OIL_PAINTING",
"CYBERPUNK",
"FANTASY",
"ANIME",
"STICKMAN"
],
"type": "string",
"description": "Optional art style (default AUTOSHORTS)."
},
"duration": {
"enum": [
15,
30,
60,
90
],
"type": "number",
"description": "Target length in seconds (default 30; 90 needs a paid plan)."
},
"language": {
"type": "string",
"description": "Optional BCP-47 narration language, e.g. \"en\", \"vi\"."
}
},
"additionalProperties": false
}Read the character sheets of one of your series: each sheet is a set of AI images of one fictional character, its images (id, view, url), which sheet and which image are chosen, how many sheets the series may still make (3 in total), and the exact price of a new sheet (23 credits for 5 images of a person, 11 for an animal or mascot). Free. Use this before create_character_sheet and tell the human the price. Characters are fictional adults (or animals / mascots), AI-generated: no real or famous people, no children or anyone who looks under 18, no sexual content, no logos or protected characters (refused with CONTENT_POLICY, nothing charged). Everything made here is AI-generated and labelled as such. Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| seriesId* | string | A series id from list_series. |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series."
}
},
"additionalProperties": false
}Is this platform connected? If yes, returns the account. If not, returns connectUrl: the page that opens the platform's consent screen. Give it to the user — that consent is the only human step, once per platform; they must be signed in to the same StoryShort account as this API key — then call this again every 10 seconds (pollAfterSeconds) until connected is true and continue on your own. The link is not single-use and holds no secret. YouTube and TikTok need a paid plan (PLAN_UPGRADE_REQUIRED otherwise). Requires the "video:read" scope. Free.
| Argument | Type | Description |
|---|---|---|
| platform* | string |
{
"type": "object",
"required": [
"platform"
],
"properties": {
"platform": {
"enum": [
"YOUTUBE",
"TIKTOK"
],
"type": "string"
}
},
"additionalProperties": false
}Get the caller's current credit balance, monthly allocation and plan. Use this before create_video to confirm the account can afford a render (40 credits). Requires the "credits:read" scope (included by default in new keys); a key without it gets 403 INSUFFICIENT_SCOPE with a link to create a key that has it. Read-only, never charges credits.
No arguments.
{
"type": "object",
"required": [],
"properties": {},
"additionalProperties": false
}Read a draft: its scenes (narration, visual prompt, length), whether the narration is long enough for the target duration, and the exact render price against the current balance. Free, read-only. Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| draftId* | string |
{
"type": "object",
"required": [
"draftId"
],
"properties": {
"draftId": {
"type": "string"
}
},
"additionalProperties": false
}Read the season plan of one of your series: the plan (logline, genre, narrator voice, language, style, cast with outfits, every episode), its hash, its status (none, saved, reviewed or confirmed) and the recorded season review (a checklist with pass or fail per rule, the season price and, if it ran, the AI review). Free. An episode can only be made from a plan that is reviewed and confirmed: use this to see where the plan stands and which episodes can be quoted. Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| seriesId* | string | A series id from list_series. |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series."
}
},
"additionalProperties": false
}How YOUR OWN posted YouTube Shorts performed, per series: videos posted/measured, total/median/mean views, top 3 and bottom 3 videos (with outlierScore = views / series median), and views gained in the last 7 days vs the 7 days before. Use it to decide what to make next. Only your own videos; views come from daily YouTube snapshots; audience retention is not available. Requires the "video:read" scope. Free, read-only.
| Argument | Type | Description |
|---|---|---|
| days | integer | Only videos created in the last N days (default 30). |
| seriesId | string | One series id (from list_series). Omit for every series with posted videos. |
{
"type": "object",
"required": [],
"properties": {
"days": {
"type": "integer",
"maximum": 90,
"minimum": 1,
"description": "Only videos created in the last N days (default 30)."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "One series id (from list_series). Omit for every series with posted videos."
}
},
"additionalProperties": false
}Get the status and details of one video the caller owns, by id. While rendering, status is PENDING/GENERATING_*/RENDERING and estimatedCompletionTime (seconds) is returned. When status is COMPLETED, a playable videoUrl and thumbnailUrl are returned; when FAILED, error says why, and a failure for lack of credits adds blockedReason "INSUFFICIENT_CREDITS" with creditsNeeded, creditsAvailable and topUpUrl (it will not be retried: top up and create the video again). Requires the "video:read" scope. Read-only, never charges credits.
| Argument | Type | Description |
|---|---|---|
| id* | string | The video id returned by create_video or list_videos. |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"description": "The video id returned by create_video or list_videos."
}
},
"additionalProperties": false
}List the available content niches, art styles, video qualities and durations that create_video accepts. Use this to pick valid niche/artStyle values. Requires the "video:read" scope. Read-only, never charges credits.
No arguments.
{
"type": "object",
"required": [],
"properties": {},
"additionalProperties": false
}List the user's series (autopilot channels), newest first, with schedule, auto-post flags, active/paused state, credits per video and an estimate per month. Paginated (page, limit). Requires the "video:read" scope. Free.
| Argument | Type | Description |
|---|---|---|
| page | integer | |
| limit | integer |
{
"type": "object",
"required": [],
"properties": {
"page": {
"type": "integer",
"minimum": 1
},
"limit": {
"type": "integer",
"maximum": 100,
"minimum": 1
}
},
"additionalProperties": false
}List the connected publishing accounts (YouTube, TikTok) with username, whether they need reconnecting, the publish mode, the AI-disclosure handling and today's platform limits. Never returns tokens. For a platform that is not connected, call get_connection_status to get a connectUrl. Requires the "video:read" scope. Free.
No arguments.
{
"type": "object",
"required": [],
"properties": {},
"additionalProperties": false
}List the caller's videos, newest first, with pagination. Optionally filter by status (one of the VideoStatus values in the schema). Returns id, title, status, videoUrl, thumbnailUrl and timestamps. Requires the "video:read" scope. Read-only, never charges credits.
| Argument | Type | Description |
|---|---|---|
| limit | number | Max videos to return (default 20, max 100). |
| offset | number | Number of videos to skip for pagination (default 0). |
| status | string | Optional status filter. |
{
"type": "object",
"required": [],
"properties": {
"limit": {
"type": "number",
"maximum": 100,
"minimum": 1,
"description": "Max videos to return (default 20, max 100)."
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Number of videos to skip for pagination (default 0)."
},
"status": {
"enum": [
"PENDING",
"GENERATING_SCRIPT",
"GENERATING_VOICE",
"FETCHING_MEDIA",
"RENDERING",
"COMPLETED",
"FAILED"
],
"type": "string",
"description": "Optional status filter."
}
},
"additionalProperties": false
}Pause a series: the scheduler stops making (and charging for) its videos until resume_series. Videos already made are untouched. Requires the "video:create" scope. Free.
| Argument | Type | Description |
|---|---|---|
| seriesId* | string | Series id (or slug). |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"seriesId": {
"type": "string",
"description": "Series id (or slug)."
}
},
"additionalProperties": false
}Drama Studio writers room: turn a one-line premise into a short-drama season: a character bible (1-4 original fictional characters: name, role, look) and 2-8 episode scripts, each with a title, a logline, a script and a "cliffhangerLine". The cliffhanger is SPOKEN: the script's last sentence is exactly "cliffhangerLine" (an open hook for every episode but the last; a payoff plus one lingering question for the last), the first sentence is a hook and the next episode picks the hook up. Each script is already sized to pass quote_character_episode (30-60 seconds of narration); an episode that could not be made to fit comes back with needsEditing: true and the exact limit in `issue`. FREE: it spends no credits, starts nothing and saves nothing (it is limited per hour). Characters are fictional adults (or animals / mascots), AI-generated: no real or famous people, no children or anyone who looks under 18, no sexual content, no logos or protected characters (refused with CONTENT_POLICY, nothing charged). Everything made here is AI-generated and labelled as such. Next steps: create_series (startPaused: true; its name is only a label), create_character_sheet with the main character as `description` (show the human the price first), then save_season_plan (the whole season: cast, voice, style, every episode), review it, get the human's yes and confirm it; only then quote_character_episode and create_character_episode per episode. Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| genre* | string | drama, thriller, comedy, horror or romance. |
| premise* | string | The story in one to three sentences: who, what they want, what goes wrong. |
| episodes* | integer |
Publish one of the user's COMPLETED videos. YOUTUBE: uploads to the connected channel with your title/description and privacy (public, unlisted, private); the "altered or synthetic content" disclosure is always set; madeForKids is the user's COPPA answer (ask them for a kids audience); nothing is appended to the description unless addAttribution is true (default false — only when the user asked for "Made with StoryShort"). TIKTOK: sends the video to the creator's TikTok Drafts (inbox) — they add the caption, switch on the AI-generated label and post in the app; pass userConsent: true only after the user agreed. Idempotent per (videoId, platform): a repeat returns the first result and never posts twice (a video already posted from the website counts). Respects platform caps (YouTube ≈5 uploads/day; TikTok's pending-drafts limit). Not connected → NOT_CONNECTED with a connectUrl. Requires the "video:create" scope. Free.
| Argument | Type | Description |
|---|---|---|
| title | string | YouTube title (cleaned and cut to 60 characters on a word). Defaults to the video title. |
| privacy | string | YouTube visibility (default public). |
| videoId* | string | |
| platform* | string | |
| description | string | YouTube description. #Shorts is added if missing. |
| madeForKids | boolean | YouTube COPPA declaration. Omit to use the series answer, or the niche default. |
Price one PLANNED episode (30-60 seconds, 3-8 shots) of a series with a confirmed season plan, starring the character the plan names. FREE: it spends nothing and starts nothing. Returns the shot plan (narration, action, camera and seconds of every shot), the exact credits (up to 325 credits for a default 30-second episode; longer ones (up to 60 seconds) cost more: an AI clip per shot, a still per shot and the narration), and a ready-made nextAction for create_character_episode. Show the human the price and the shots, and call the create tool only after they say yes. The same safety checks as the real call run here: real or famous people, anyone who looks under 18, sexual content and protected characters are refused with CONTENT_POLICY. Only an episode of a REVIEWED, CONFIRMED season plan can be quoted or made: send its script or shots exactly as planned (get_season_plan). Without a confirmed plan the answer is SEASON_PLAN_REQUIRED or SEASON_NOT_REVIEWED, and for shots that are not a planned episode EPISODE_NOT_IN_PLAN, each with a nextAction. The narrator voice, the language, the style and the character come from the plan and cannot be overridden (SEASON_FIELD_LOCKED); to change an episode, edit the plan (that clears the review). Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| shots | array | The shots of the planned episode. Give `shots` OR `script`. |
| title | string | Optional title. |
| script | string | The narration, about 74-147 words. The system splits it into shots by sentence. Give `script` OR `shots`, exactly as planned (get_season_plan). |
| sheetId | string |
The exact credit price of a video with AI motion clips BEFORE it is made, and whether this account may make it. Read-only: nothing is created, reserved or charged, and no prompt is checked. Returns baseCredits (the normal video), motionCredits (40 credits per motion scene, each a 5-second clip, on top of the normal video price), totalCredits, the balance and whether it covers the total, maxMotionScenes for this account and, when it cannot be made, code + reason (MOTION_PLAN_REQUIRED: FREE plans cannot use motion; MOTION_TRIAL_LIMIT; MOTION_CLIPS_DISABLED). Trial accounts (no payment yet) get 1 AI clip in total (MOTION_TRIAL_LIMIT after that); a payment unlocks the rest. Motion scenes that cannot be made fall back to a still image with their credits refunded. Pass the same motion_scenes to create_video. Requires the "video:read" scope.
| Argument | Type | Description |
|---|---|---|
| language | string | Optional BCP-47 code (e.g. "en", "fa"). A language only ElevenLabs speaks adds its voice premium to baseCredits. |
| motion_scenes | integer | How many scenes to price as AI clips (default 1). |
{
"type": "object",
"required": [],
"properties": {
"language": {
"type": "string",
"description": "Optional BCP-47 code (e.g. \"en\", \"fa\"). A language only ElevenLabs speaks adds its voice premium to baseCredits."
},
"motion_scenes": {
"type": "integer",
"maximum": 3,
"minimum": 0,
"description": "How many scenes to price as AI clips (default 1)."
}
},
"additionalProperties": false
}Render an approved draft into the video. THIS IS THE ONLY STEP THAT COSTS CREDITS: the price is quote.credits from get_draft / draft_video, charged once after the render succeeds (a failed attempt costs nothing; StoryShort may retry a failed render automatically, up to 3 times, and the same video is never charged twice — cancel_video stops the retries). Call it first without confirmCredits to get QUOTE_REQUIRED and the price, show the user, then call again with confirmCredits set to that exact number. A wrong number is refused (PRICE_CHANGED); a short balance is refused up front (INSUFFICIENT_CREDITS). Calling it again on a draft that is already rendering starts nothing new. Poll get_video until COMPLETED or FAILED. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| draftId* | string | |
| confirmCredits | integer | The render price in credits the user approved (quote.credits). |
{
"type": "object",
"required": [
"draftId"
],
"properties": {
"draftId": {
"type": "string"
},
"confirmCredits": {
"type": "integer",
"minimum": 0,
"description": "The render price in credits the user approved (quote.credits)."
}
},
"additionalProperties": false
}Resume a paused series. Refused with SERIES_NEEDS_CREDITS when the balance cannot pay the next video, and with SERIES_LIMIT_REACHED at 5 active series. Creating or changing a series is FREE. While active, the scheduler makes one video every scheduleIntervalDays (the first at its next run, within about 30 minutes) and charges each video like any video, 40 credits with the default render, at render time. It needs at least 40 credits in the balance: when the balance cannot pay for the next video the scheduler PAUSES the series (it never overdraws), so create_series and resume_series refuse with SERIES_NEEDS_CREDITS instead of making a series that would never run. Agents may keep at most 5 series active at once (SERIES_LIMIT_REACHED). StoryShort has no per-key daily spending cap: pause_series is the brake. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| seriesId* | string | Series id (or slug). |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"seriesId": {
"type": "string",
"description": "Series id (or slug)."
}
},
"additionalProperties": false
}Change ONE scene of a draft in place: its narration (scriptText), its visualPrompt and/or its durationSeconds. Scene numbers start at 1 (see get_draft). Only the fields you pass change. Screened like any prompt. Free; draft only. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| scene* | integer | Scene number, starting at 1. |
| draftId* | string | |
| scriptText | string | The narration of this scene, exactly as it will be spoken. |
| visualPrompt | string | What the image should show. Leave empty to let StoryShort write it at render. |
| durationSeconds | number | Scene length (default 10). |
{
"type": "object",
"required": [
"draftId",
"scene"
],
"properties": {
"scene": {
"type": "integer",
"maximum": 12,
"minimum": 1,
"description": "Scene number, starting at 1."
},
"draftId": {
"type": "string"
},
"scriptText": {
"type": "string",
"maxLength": 1000,
"description": "The narration of this scene, exactly as it will be spoken."
},
"visualPrompt": {
"type": "string",
"maxLength": 600,
"description": "What the image should show. Leave empty to let StoryShort write it at render."
},
"durationSeconds": {
"type": "number",
"maximum": 30,
"minimum": 2,
"description": "Scene length (default 10)."
}
},
"additionalProperties": false
}Design, review and confirm the WHOLE season of a series before any episode is made. Free (no credits). A series is fully designed and reviewed before any video is produced, and its characters, voice and style are fixed in every episode. Three steps, one tool: (1) pass `plan` to save it (version 1: logline, genre, language, narratorVoiceId, styleTokens, characters[] with look, sheetId and wardrobeLock, rules[], at least 3 episodes[] with title, characterName, cliffhangerLine and shots[] or a script). Every edit clears the review and the confirmation. (2) pass `review: true` (with or without `plan`) to run the season review: a deterministic checklist (cliffhangers, hooks, one narrator and style, no on-screen text, one subject per look and per shot, outfit locked, season price) plus an advisory AI review that lists up to 8 concrete issues; if the AI review cannot run the answer says so and the checklist stands. (3) show the human the checklist, the AI issues and the season price, and ONLY after they say yes call again with `confirm: true` and `planHash` from the review. Every character an episode uses needs a READY sheet of this series (create_character_sheet, one sheet per character) whose id is in the plan. Then quote_character_episode / create_character_episode make the planned episodes. Characters are fictional adults (or animals / mascots), AI-generated: no real or famous people, no children or anyone who looks under 18, no sexual content, no logos or protected characters (refused with CONTENT_POLICY, nothing charged). Everything made here is AI-generated and labelled as such. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| plan | object | The whole season plan. Omit to review or confirm the stored one. |
| review | boolean | Run the season review on the stored plan (after saving `plan` if given). |
| confirm |
Choose which character sheet a series uses and which of its images is the main one. The main image is the reference every still of an episode is made from. Only your own READY sheets and their images can be chosen. Free. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| assetId | string | An image id of that sheet to make the main image. Omit to keep the current main image. |
| sheetId* | string | A sheet id from get_character_sheet. |
| seriesId* | string |
{
"type": "object",
"required": [
"seriesId",
"sheetId"
],
"properties": {
"assetId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "An image id of that sheet to make the main image. Omit to keep the current main image."
},
"sheetId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A sheet id from get_character_sheet."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1
}
},
"additionalProperties": false
}Change a draft: its title and/or REPLACE all its scenes (1-12, each with scriptText and optional visualPrompt / durationSeconds). The narration you send is exactly what is spoken. To change one scene use revise_scene. Edits are screened like any prompt. Free; works only while the draft has not been rendered. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| title | string | |
| scenes | array | The complete new scene list (replaces the old one). |
| draftId* | string |
{
"type": "object",
"required": [
"draftId"
],
"properties": {
"title": {
"type": "string",
"maxLength": 100
},
"scenes": {
"type": "array",
"items": {
"type": "object",
"required": [
"scriptText"
],
"properties": {
"scriptText": {
"type": "string",
"maxLength": 1000,
"description": "The narration of this scene, exactly as it will be spoken."
},
"visualPrompt": {
"type": "string",
"maxLength": 600,
"description": "What the image should show. Leave empty to let StoryShort write it at render."
},
"durationSeconds": {
"type": "number",
"maximum": 30,
"minimum": 2,
"description": "Scene length (default 10)."
}
},
"additionalProperties": false
},
"maxItems": 12,
"minItems": 1,
"description": "The complete new scene list (replaces the old one)."
},
"draftId": {
"type": "string"
}
},
"additionalProperties": false
}Change a series: how often it runs, YouTube auto-post, the madeForKids answer or the language. Only the fields you pass change. The name and niche cannot be changed (create a new series). Making an ACTIVE series run more often raises its spend, so it goes through the same credit check as resume_series. Creating or changing a series is FREE. While active, the scheduler makes one video every scheduleIntervalDays (the first at its next run, within about 30 minutes) and charges each video like any video, 40 credits with the default render, at render time. It needs at least 40 credits in the balance: when the balance cannot pay for the next video the scheduler PAUSES the series (it never overdraws), so create_series and resume_series refuse with SERIES_NEEDS_CREDITS instead of making a series that would never run. Agents may keep at most 5 series active at once (SERIES_LIMIT_REACHED). StoryShort has no per-key daily spending cap: pause_series is the brake. Requires the "video:create" scope.
| Argument | Type | Description |
|---|---|---|
| language | string | |
| seriesId* | string | Series id (or slug) from list_series. |
| madeForKids | boolean | |
| autoPostYouTube | boolean | |
| scheduleIntervalDays | integer |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"language": {
"type": "string",
"maxLength": 10
},
"seriesId": {
"type": "string",
"description": "Series id (or slug) from list_series."
},
"madeForKids": {
"type": "boolean"
},
"autoPostYouTube": {
"type": "boolean"
},
"scheduleIntervalDays": {
"type": "integer",
"maximum": 30,
"minimum": 1
}
},
"additionalProperties": false
}We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 12, 2026.
{
"type": "object",
"required": [
"seriesId",
"confirm",
"expectedCredits",
"idempotencyKey"
],
"properties": {
"shots": {
"type": "array",
"items": {
"type": "object",
"required": [
"narration"
],
"properties": {
"action": {
"type": "string",
"maxLength": 300,
"description": "What the viewer sees the character doing. Omit to illustrate the narration."
},
"camera": {
"type": "string",
"maxLength": 120,
"description": "Camera: wide shot, close-up, push-in, over-the-shoulder... Omit for an automatic choice."
},
"narration": {
"type": "string",
"maxLength": 600,
"description": "What the narrator says over this shot."
}
},
"additionalProperties": false
},
"maxItems": 8,
"minItems": 3,
"description": "The shots of the planned episode. Give `shots` OR `script`."
},
"title": {
"type": "string",
"maxLength": 80,
"description": "Optional title."
},
"script": {
"type": "string",
"maxLength": 2400,
"minLength": 120,
"description": "The narration, about 74-147 words. The system splits it into shots by sentence. Give `script` OR `shots`, exactly as planned (get_season_plan)."
},
"confirm": {
"enum": [
true
],
"type": "boolean",
"description": "Must be true: making an episode spends credits, and the human has seen the price."
},
"sheetId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "Omit it: the character sheet is the one the season plan names for this episode. If given it must equal that sheet."
},
"language": {
"type": "string",
"maxLength": 12,
"description": "Omit it: the narration language is the season plan's. If given it must equal the plan's."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series whose season plan is reviewed and confirmed."
},
"shotCount": {
"type": "integer",
"maximum": 8,
"minimum": 3,
"description": "With `script`: how many shots to split it into. Omit for an automatic count."
},
"idempotencyKey": {
"type": "string",
"maxLength": 200,
"minLength": 8,
"description": "Required. One new unique key per purchase; a repeat with the same key returns the first answer (replayed: true) and charges nothing."
},
"expectedCredits": {
"type": "integer",
"minimum": 1,
"description": "The credits the quote showed the human. Must match the price computed now."
}
},
"additionalProperties": false
}| imageCount | integer | Images in the sheet (default 5). |
| description | string | The character's look: age band, hair, outfit, colours. Omit to use the series' saved character description. |
| subjectKind | string | PERSON (fictional adult, default), ANIMAL (pet) or MASCOT. |
| idempotencyKey* | string | Required. One new unique key per purchase; a repeat with the same key returns the first answer (replayed: true) and charges nothing. |
| expectedCredits* | integer | The price the human saw (get_character_sheet quotes for this kind and image count). Must equal the price computed now. |
{
"type": "object",
"required": [
"seriesId",
"confirm",
"expectedCredits",
"idempotencyKey"
],
"properties": {
"confirm": {
"enum": [
true
],
"type": "boolean",
"description": "Must be true: making a sheet spends credits, and the human has seen the price."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series."
},
"imageCount": {
"type": "integer",
"maximum": 6,
"minimum": 4,
"description": "Images in the sheet (default 5)."
},
"description": {
"type": "string",
"maxLength": 400,
"minLength": 8,
"description": "The character's look: age band, hair, outfit, colours. Omit to use the series' saved character description."
},
"subjectKind": {
"enum": [
"PERSON",
"ANIMAL",
"MASCOT"
],
"type": "string",
"description": "PERSON (fictional adult, default), ANIMAL (pet) or MASCOT."
},
"idempotencyKey": {
"type": "string",
"maxLength": 200,
"minLength": 8,
"description": "Required. One new unique key per purchase; a repeat with the same key returns the first answer (replayed: true) and charges nothing."
},
"expectedCredits": {
"type": "integer",
"minimum": 1,
"description": "The price the human saw (get_character_sheet quotes for this kind and image count). Must equal the price computed now."
}
},
"additionalProperties": false
}| Narration language code, e.g. "en" (default). |
| madeForKids | boolean | COPPA answer for YouTube uploads from this series. Ask the user. |
| startPaused | boolean | Create without generating until resume_series. |
| idempotencyKey | string | Retry-safe: a repeat with the same key returns the first answer (replayed: true). |
| autoPostYouTube | boolean | Upload each finished video to the connected YouTube channel. |
| defaultDuration | integer | Seconds per video; longer lengths need a paid plan. |
| scheduleIntervalDays | integer | One video every N days (default 1 = daily). |
{
"type": "object",
"required": [
"name",
"niche"
],
"properties": {
"name": {
"type": "string",
"maxLength": 200,
"minLength": 1,
"description": "The series topic/name; every video is generated from it."
},
"niche": {
"enum": [
"MOTIVATIONAL",
"SCARY_STORIES",
"AI_FACTS",
"HISTORY_FACTS",
"REDDIT_STORIES",
"LIFE_HACKS",
"CRYPTO_FINANCE",
"PSYCHOLOGY_FACTS",
"PERSONAL_FINANCE",
"FUNNY_STORIES",
"LOVE_STORIES",
"BRAINROT",
"ANIME",
"UGC_ADS",
"DOCUMENTARY",
"ASMR",
"POV",
"MOVIE_MAKER",
"MUSIC_VIDEO"
],
"type": "string",
"description": "Content niche (list_niches)."
},
"quality": {
"enum": [
"HD_720",
"FULL_HD_1080"
],
"type": "string"
},
"language": {
"type": "string",
"maxLength": 10,
"description": "Narration language code, e.g. \"en\" (default)."
},
"madeForKids": {
"type": "boolean",
"description": "COPPA answer for YouTube uploads from this series. Ask the user."
},
"startPaused": {
"type": "boolean",
"description": "Create without generating until resume_series."
},
"idempotencyKey": {
"type": "string",
"maxLength": 200,
"minLength": 8,
"description": "Retry-safe: a repeat with the same key returns the first answer (replayed: true)."
},
"autoPostYouTube": {
"type": "boolean",
"description": "Upload each finished video to the connected YouTube channel."
},
"defaultDuration": {
"enum": [
10,
60,
90
],
"type": "integer",
"description": "Seconds per video; longer lengths need a paid plan."
},
"scheduleIntervalDays": {
"type": "integer",
"maximum": 30,
"minimum": 1,
"description": "One video every N days (default 1 = daily)."
}
},
"additionalProperties": false
}| Target length in seconds for the multi-scene faceless video: 30, 60 or 90 (default 30). |
| language | string | Optional BCP-47 language code (e.g. "en", "vi", "es"). Defaults to "auto". |
| motion_scenes | integer | Optional. How many scenes (from the first) to animate as AI clips. 40 credits each, on top of the video price. Default 0. |
{
"type": "object",
"required": [
"topic"
],
"properties": {
"niche": {
"enum": [
"MOTIVATIONAL",
"SCARY_STORIES",
"AI_FACTS",
"HISTORY_FACTS",
"REDDIT_STORIES",
"LIFE_HACKS",
"CRYPTO_FINANCE",
"PSYCHOLOGY_FACTS",
"PERSONAL_FINANCE",
"FUNNY_STORIES",
"LOVE_STORIES",
"BRAINROT",
"ANIME",
"UGC_ADS",
"DOCUMENTARY",
"ASMR",
"POV",
"MOVIE_MAKER",
"MUSIC_VIDEO"
],
"type": "string",
"description": "Optional content niche. Call list_niches for the authoritative list with labels."
},
"topic": {
"type": "string",
"maxLength": 500,
"description": "What the video is about. The full script is AI-generated from this. e.g. \"3 tiny habits that quietly change your life\"."
},
"artStyle": {
"enum": [
"AUTOSHORTS",
"LEGO",
"COMIC_BOOK",
"DISNEY_TOON",
"STUDIO_GHIBLI",
"PIXEL_ART",
"WATERCOLOR",
"OIL_PAINTING",
"CYBERPUNK",
"FANTASY",
"ANIME",
"STICKMAN"
],
"type": "string",
"description": "Optional visual art style. Defaults to AUTOSHORTS (cinematic). Call list_niches for the full list."
},
"duration": {
"enum": [
30,
60,
90
],
"type": "number",
"description": "Target length in seconds for the multi-scene faceless video: 30, 60 or 90 (default 30)."
},
"language": {
"type": "string",
"description": "Optional BCP-47 language code (e.g. \"en\", \"vi\", \"es\"). Defaults to \"auto\"."
},
"motion_scenes": {
"type": "integer",
"maximum": 3,
"minimum": 0,
"description": "Optional. How many scenes (from the first) to animate as AI clips. 40 credits each, on top of the video price. Default 0."
}
},
"additionalProperties": false
}| How many episodes. |
| language | string | Language code of the scripts, such as 'en' or 'vi'. Default 'en'. |
{
"type": "object",
"required": [
"premise",
"genre",
"episodes"
],
"properties": {
"genre": {
"enum": [
"drama",
"thriller",
"comedy",
"horror",
"romance"
],
"type": "string",
"description": "drama, thriller, comedy, horror or romance."
},
"premise": {
"type": "string",
"maxLength": 600,
"minLength": 20,
"description": "The story in one to three sentences: who, what they want, what goes wrong."
},
"episodes": {
"type": "integer",
"maximum": 8,
"minimum": 2,
"description": "How many episodes."
},
"language": {
"type": "string",
"maxLength": 12,
"description": "Language code of the scripts, such as 'en' or 'vi'. Default 'en'."
}
},
"additionalProperties": false
}| userConsent | boolean | TikTok only: the user agreed to send this video to their TikTok drafts. |
| addAttribution | boolean | YouTube only. Append "Made with StoryShort", a link and #StoryShort to the description. Default false: set true ONLY if the user explicitly asked for it. |
{
"type": "object",
"required": [
"videoId",
"platform"
],
"properties": {
"title": {
"type": "string",
"maxLength": 100,
"description": "YouTube title (cleaned and cut to 60 characters on a word). Defaults to the video title."
},
"privacy": {
"enum": [
"public",
"unlisted",
"private"
],
"type": "string",
"description": "YouTube visibility (default public)."
},
"videoId": {
"type": "string"
},
"platform": {
"enum": [
"YOUTUBE",
"TIKTOK"
],
"type": "string"
},
"description": {
"type": "string",
"maxLength": 4900,
"description": "YouTube description. #Shorts is added if missing."
},
"madeForKids": {
"type": "boolean",
"description": "YouTube COPPA declaration. Omit to use the series answer, or the niche default."
},
"userConsent": {
"type": "boolean",
"description": "TikTok only: the user agreed to send this video to their TikTok drafts."
},
"addAttribution": {
"type": "boolean",
"description": "YouTube only. Append \"Made with StoryShort\", a link and #StoryShort to the description. Default false: set true ONLY if the user explicitly asked for it."
}
},
"additionalProperties": false
}| Omit it: the character sheet is the one the season plan names for this episode. If given it must equal that sheet. |
| language | string | Omit it: the narration language is the season plan's. If given it must equal the plan's. |
| seriesId* | string | A series id from list_series whose season plan is reviewed and confirmed. |
| shotCount | integer | With `script`: how many shots to split it into. Omit for an automatic count. |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"shots": {
"type": "array",
"items": {
"type": "object",
"required": [
"narration"
],
"properties": {
"action": {
"type": "string",
"maxLength": 300,
"description": "What the viewer sees the character doing. Omit to illustrate the narration."
},
"camera": {
"type": "string",
"maxLength": 120,
"description": "Camera: wide shot, close-up, push-in, over-the-shoulder... Omit for an automatic choice."
},
"narration": {
"type": "string",
"maxLength": 600,
"description": "What the narrator says over this shot."
}
},
"additionalProperties": false
},
"maxItems": 8,
"minItems": 3,
"description": "The shots of the planned episode. Give `shots` OR `script`."
},
"title": {
"type": "string",
"maxLength": 80,
"description": "Optional title."
},
"script": {
"type": "string",
"maxLength": 2400,
"minLength": 120,
"description": "The narration, about 74-147 words. The system splits it into shots by sentence. Give `script` OR `shots`, exactly as planned (get_season_plan)."
},
"sheetId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "Omit it: the character sheet is the one the season plan names for this episode. If given it must equal that sheet."
},
"language": {
"type": "string",
"maxLength": 12,
"description": "Omit it: the narration language is the season plan's. If given it must equal the plan's."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series whose season plan is reviewed and confirmed."
},
"shotCount": {
"type": "integer",
"maximum": 8,
"minimum": 3,
"description": "With `script`: how many shots to split it into. Omit for an automatic count."
}
},
"additionalProperties": false
}| boolean |
| The owner confirms the reviewed plan. Needs planHash; do not send `plan` in the same call. |
| aiReview | boolean | With review: also run the advisory AI review (default true). |
| planHash | string | With confirm: the planHash the review returned. |
| seriesId* | string | A series id from list_series. |
{
"type": "object",
"required": [
"seriesId"
],
"properties": {
"plan": {
"type": "object",
"required": [
"version",
"logline",
"genre",
"language",
"narratorVoiceId",
"styleTokens",
"characters",
"episodes"
],
"properties": {
"genre": {
"enum": [
"drama",
"thriller",
"comedy",
"horror",
"romance"
],
"type": "string"
},
"rules": {
"type": "array",
"items": {
"type": "string",
"maxLength": 300
},
"maxItems": 16
},
"title": {
"type": "string",
"maxLength": 80
},
"logline": {
"type": "string",
"maxLength": 300,
"minLength": 10
},
"version": {
"enum": [
1
],
"type": "integer"
},
"episodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"n",
"title",
"characterName",
"cliffhangerLine"
],
"properties": {
"n": {
"type": "integer",
"maximum": 12,
"minimum": 1
},
"shots": {
"type": "array",
"items": {
"type": "object",
"required": [
"narration"
],
"properties": {
"action": {
"type": "string",
"maxLength": 300,
"description": "What the viewer sees: ONE character, one action. Never on-screen text."
},
"camera": {
"type": "string",
"maxLength": 120,
"description": "Camera: shot size and one move."
},
"narration": {
"type": "string",
"maxLength": 600,
"description": "What the narrator says over this shot."
}
},
"additionalProperties": false
},
"maxItems": 8,
"minItems": 3,
"description": "Shots you write. Give `shots` OR `script`."
},
"title": {
"type": "string",
"maxLength": 80
},
"script": {
"type": "string",
"maxLength": 2400,
"description": "The narration the system splits into shots. Give `script` OR `shots`."
},
"logline": {
"type": "string",
"maxLength": 300
},
"characterName": {
"type": "string",
"maxLength": 40,
"description": "The ONE character of the cast this episode stars."
},
"cliffhangerLine": {
"type": "string",
"maxLength": 200,
"description": "The LAST spoken sentence of every episode but the last."
}
},
"additionalProperties": false
},
"maxItems": 12,
"minItems": 1
},
"language": {
"type": "string",
"maxLength": 12,
"description": "The narration language of every episode: 'en', 'vi'... (never auto)."
},
"characters": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"look",
"wardrobeLock"
],
"properties": {
"look": {
"type": "string",
"maxLength": 400,
"minLength": 8,
"description": "ONE character: age band, hair, outfit, one prop. Never two characters in one look."
},
"name": {
"type": "string",
"maxLength": 40
},
"role": {
"type": "string",
"maxLength": 120
},
"sheetId": {
"type": [
"string",
"null"
],
"description": "The READY character sheet of THIS series that plays this character."
},
"wardrobeLock": {
"type": "string",
"maxLength": 200,
"minLength": 3,
"description": "The outfit, identical in every episode (\"natural fur, no clothes\" for an animal)."
},
"expressionRule": {
"type": "string",
"maxLength": 200
}
},
"additionalProperties": false
},
"maxItems": 6,
"minItems": 1
},
"styleTokens": {
"type": "string",
"maxLength": 160,
"minLength": 3,
"description": "One short phrase appended to every shot prompt, e.g. \"cinematic, moody teal light, 35mm film\"."
},
"narratorVoiceId": {
"type": "string",
"maxLength": 64,
"minLength": 3,
"description": "The narrator of every episode: an ElevenLabs voice id or a Google voice name such as en-US-Chirp3-HD-Aoede."
}
},
"description": "The whole season plan. Omit to review or confirm the stored one.",
"additionalProperties": false
},
"review": {
"type": "boolean",
"description": "Run the season review on the stored plan (after saving `plan` if given)."
},
"confirm": {
"type": "boolean",
"description": "The owner confirms the reviewed plan. Needs planHash; do not send `plan` in the same call."
},
"aiReview": {
"type": "boolean",
"description": "With review: also run the advisory AI review (default true)."
},
"planHash": {
"type": "string",
"maxLength": 64,
"minLength": 64,
"description": "With confirm: the planHash the review returned."
},
"seriesId": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"description": "A series id from list_series."
}
},
"additionalProperties": false
}