Videos

The core loop of the ShortFast API: pick a pipeline, write a brief, queue generation, poll it, render, and download.

A video is one document that carries the brief you sent, the assets the pipeline produced, and two independent jobs: generation (process) and render (render). Everything else in the API hangs off it.

Generation and rendering are asynchronous. No endpoint waits for a job: POST /videos returns as soon as the work is queued, and a generation takes minutes. Poll GET /videos/{id}, or subscribe to video.generation_completed and let the webhook tell you.

Pick a pipeline

type selects the pipeline and subType the variant. Four combinations can be created from a JSON brief:

typesubTypeWhat it makes
facelessgenericA written script, a voiceover, captions, and stock footage or AI images cut against the transcript. The default short-form video.
facelesspresentationA narrated presentation cut into scenes, each one rendered by a visual template on a branded backdrop.
aigenericA sequence of AI shots: one still and one motion prompt per scene, with narration spoken over it.
aiugcThe same AI pipeline, built around one recurring character image reused across every scene.

A third type exists on read: video is an uploaded source file running the editable pipeline. It cannot be created here, because a JSON brief cannot supply the file. POST /videos/{id}/convert turns a finished ai video into one.

The brief

Send the brief flat, or nested under brief. The nested form wins, so a serialized video can be posted straight back. Unknown keys are ignored; a known key with a malformed value is a 400.

FieldValues and limits
title200 characters
prompt500 characters. What the video is about
inputModeidea writes the script from prompt; script uses the text you supply
textThe script. 2000 characters on short, 15000 on long, and at most 120 spoken words on a presentation
scriptPrompt500 characters. Steering for the script writer
customInstructions300 characters
videoDurationshort or long. long (8 to 15 minutes) needs an Advanced plan
aspectRatio9:16, 4:5, 1:1, 16:9
languageauto, or a code such as en or pt-BR (10 characters)
imageStylestock_footage, realistic, mixed, custom
customStyleText100 characters. Read when imageStyle is custom
voiceIdAn id from GET /reference/voices
voiceProvideropenai or gemini. The gemini tier is the premium expressive one and costs more per minute
moodenergetic, inspiring, suspenseful, thrilling, calm. The music bed
showSubtitlesWhether captions render over the video
description300 characters. The social caption a publish posts with the video
descriptionPrompt500 characters. Steering for the caption writer
configThe theme block, same shape the editor reads

Presentation videos add presentationTone (an id from GET /reference/presentation-tones) and presentationAssets: up to 8 entries of { type: "image" | "video", url, description } for the director to place on a scene.

AI videos add targetDuration (5 to 60 seconds), and UGC videos add characterImageUrl and characterDescription (2000 characters) for the recurring character.

Build a valid brief against the reference lists rather than hardcoding: /reference/voices, /reference/presentation-tones, /reference/presentation-templates, /reference/presentation-backgrounds, /reference/aspect-ratios and /reference/image-styles are static and unpaginated.

Job flags

process carries the per-run job flags. They live on the job, never on the brief, and an omitted flag keeps whatever the video already has:

FlagEffect
transcribeTranscribe the audio into the word-level caption track
addBRollsCut the script into b-roll segments and resolve media for each
renderQueue the render as soon as generation finishes, without a second call

1. Create and queue generation

curl -X POST https://app.shortfast.com/api/v1/videos \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4f1c9e2a-6b81-4f0d-9a3e-2c5d7e8b1a44" \
  -d '{
    "type": "faceless",
    "subType": "generic",
    "prompt": "Why founders burn out and what to do about it",
    "inputMode": "idea",
    "videoDuration": "short",
    "aspectRatio": "9:16",
    "language": "en",
    "imageStyle": "mixed",
    "voiceId": "Enceladus",
    "voiceProvider": "gemini",
    "mood": "inspiring",
    "showSubtitles": true,
    "process": { "transcribe": true, "addBRolls": true, "render": true }
  }'

The response is the whole video with process.status: "QUEUED". Generation charges credits and counts against the monthly generation limit, so it can be refused before the job is queued with warning-no-credits, warning-plan-generations, warning-plan-storage or warning-plan-duration. isAutomation is refused here: create a blueprint with POST /automations instead (see Automations).

To requeue generation on a video that already exists, POST /videos/{id}/process with the flags alone. A video whose generation is already QUEUED or STARTED is refused with warning-already-processing.

2. Poll until generation finishes

curl https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Both jobs report the same four statuses, plus a progress percentage:

StatusMeaning
QUEUEDAccepted and waiting for a worker
STARTEDRunning. process.statusText names the step in plain words
COMPLETEDFinished
FAILEDStopped. error.code, error.blocked and error.action say why and what clears it

Poll every few seconds. A FAILED job with error.blocked: true is an expected limit rather than a crash, and error.action (upgrade, credits, connect, configure, none) is the fix.

GET /videos collapses both jobs into one status you can filter on, in this precedence: failed if either job failed, then rendering, then processing, then ready (a render exists), otherwise draft. The list also accepts type, subType and q (a case-insensitive title search).

3. Render, poll, download

Once process.status is COMPLETED, queue the render, poll it, and ask for a download URL. That half of the loop is covered in Rendering and download.

curl -X POST https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/render \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 8c3f1b90-77aa-4e51-b0d2-1e9f4a6c2d33"

Passing process.render: true at creation chains this automatically, so a one-shot integration only ever polls for status: "ready".

Reading a video back

GET /videos/{id} omits the content arrays by default, because they dominate the payload. Opt into the ones you need:

curl "https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv?include=captions,captionsPages" \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Known keys are captions, captionsPages, bRolls, presentationScenes and scenes. An unknown key is dropped rather than rejected, so a newer client still gets its video. An include passed to the list endpoint is ignored: the heavy arrays never ride on a list.

Editing an existing video

PATCH /videos/{id} accepts only the brief fields that still mean something once a video exists: title, aspectRatio, showSubtitles, description, descriptionPrompt, prompt, subType, targetDuration, characterImageUrl and characterDescription.

Every other brief field is generation-time only and is refused with a 400 naming it, rather than silently dropped. Editing does not requeue anything: run POST /videos/{id}/process or POST /videos/{id}/render afterwards if the change should reach the output.

Rewriting the script or the caption

Two synchronous writers charge one generation's worth of credits each and store their result on the brief:

  • POST /videos/{id}/script writes brief.text. Pass prompt to restate what the script should be about; it is saved as scriptPrompt and reused next time.
  • POST /videos/{id}/description writes brief.description, the caption a publish posts alongside the video. Pass prompt to steer it; it is saved as descriptionPrompt.

Both return the finished text in the response. A writer that returns nothing usable is a 502: retry in a moment.

Clips and variations

POST /videos/{id}/clips creates a new video from this one, pointing back at it through parentVideoId:

curl -X POST https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/clips \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "regenerate": true, "render": true }'

regenerate: true rewrites the script and visuals (charging credits) instead of reusing them. render: true queues the render as soon as the clip is ready. GET /videos/{id}/clips lists what a video has produced, sorted on creation time so a running job cannot shuffle rows between two pages of the same walk.

Deleting

DELETE /videos/{id} removes the video, every clip made from it, and the stored files they own, then credits the freed bytes back to the workspace storage quota. It cannot be undone, and the response reports deletedClips and freedBytes.

Reference

On this page