Editor
Edit the artifacts one video is made of: its theme config, transcript, caption pages, b-roll segments, presentation timeline and AI scenes.
Everything the generation pipeline produced is editable through a set of
endpoints nested under /videos/{id}. They are all arrays or objects on the
video document, so each one is read and written whole rather than patched item by
item.
| Artifact | Endpoint | Exists on |
|---|---|---|
| Theme config | /videos/{id}/config | Every video |
| Transcript and caption pages | /videos/{id}/captions | Videos generated with transcribe |
| B-roll segments | /videos/{id}/brolls | Videos generated with addBRolls |
| Presentation timeline | /videos/{id}/presentation-scenes | subType: presentation only |
| AI scenes | /videos/{id}/scenes | type: ai only |
Reading an artifact on the wrong pipeline is a 409 wrong-video-type. The same
arrays can be read alongside the video itself with
GET /videos/{id}?include=captions,bRolls,..., which is cheaper than four calls
when you only need to look.
Read, modify, write
PUT replaces the whole array. An item you leave out of the body is deleted, so
never construct an array from scratch: GET the current one, change what you
need, and PUT the full result back.
The write path is deliberately lossy. Only the fields listed below travel on the
wire, so a caller can never point a segment at an arbitrary asset or rewrite the
editor's styling. Everything else is carried over from the stored item with the
same id: an incoming item is layered on top of the one already saved, and an
item whose id is unknown (or absent) is treated as new. Ids are minted when
absent.
That merge is what makes a read-modify-write safe and a hand-built array dangerous. Post an array of fresh objects with no ids and you will keep the timings you sent and lose every resolved file, every animation and every sound effect the user chose.
Theme config
The config holds the caption styling and the presentation brand palette for one video. An empty object means the video has never been styled and renders with the editor defaults.
curl -X PATCH https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/config \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"captionsPrimaryColor": "#FFD400",
"captionsFontSize": 84,
"captionsVerticalPosition": 62
}'The config is the one artifact that merges rather than replaces: PATCH
shallow-merges the keys the body carries into the stored config and returns the
whole merged object, leaving omitted keys alone. Send the config object itself or
nest it under config. Unknown keys are dropped; a known key with a value
outside its enum or range is a 400; a body carrying no known config key at all
is refused rather than saved as a no-op.
DELETE /videos/{id}/config replaces the stored config with the editor defaults
and returns them.
Transcript and caption pages
captions is the word-level transcript the pipeline produced. captionsPages is
how those words are grouped into the chunks shown on screen. Both are empty until
the video has been generated with transcription on.
PUT accepts captions, captionsPages or both. Whichever half you send is
replaced wholesale; the other is left untouched.
curl -X PUT https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/captions \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"captionsPages": [
{ "id": "p1a2b3", "startMs": 0, "endMs": 2000 },
{ "id": "p4d5e6", "startMs": 2000, "endMs": 3620, "hidden": true }
]
}'A caption word writes id, startMs, endMs, text, punctuated_word and
confidence. A caption page writes id, startMs, endMs and hidden; its
editor decorations (emoji, audioEffect) are read-only and preserved by id.
Caps per request: 6000 caption words, 2000 pages. endMs must be at or after
startMs on every item.
B-roll segments
One segment per stretch of the video that shows footage or a generated image instead of the base video. Each segment carries both the editable brief (what it should show) and the resolved media the pipeline picked for it.
| Writable | Read-only, preserved by id |
|---|---|
id, startMs, endMs | url, type, qualityUrls |
text (the line of script it covers, 1000 characters) | animation, transition, layout, scale |
prompt (what an AI image should show, 1000 characters) | hidden, audioEffect |
keywords (search terms for stock footage, 200 characters) | |
mediaType: ai_image or stock_footage |
curl -X PUT https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/brolls \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"bRolls": [
{ "id": "b1a2b3", "startMs": 0, "endMs": 2400, "prompt": "A tired founder at a desk late at night", "mediaType": "ai_image" },
{ "startMs": 2400, "endMs": 5200, "keywords": "unfinished notebook", "mediaType": "stock_footage" }
]
}'The body can be a bare JSON array or wrapped as { "bRolls": [ ... ] }. Cap: 500
segments per request. The second segment above has no id, so it is created new
and starts with no media attached.
Changing what a segment should show does not re-fetch its media on its own.
Requeue generation with addBRolls: true (see Videos) to resolve new
footage for the changed briefs.
Presentation timeline
The scene timeline of a presentation video: one entry per beat, each with its
span in the video, the line of script it covers, and the visual template that
renders it. Template ids come from GET /reference/presentation-templates and
backdrop ids from GET /reference/presentation-backgrounds.
curl -X PUT https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/presentation-scenes \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"presentationScenes": [
{ "id": "s1a2b3", "startMs": 0, "endMs": 3200, "text": "Ship your first video in under a minute", "template": "heroTitle", "tone": "light" },
{ "id": "s4d5e6", "startMs": 3200, "endMs": 7400, "text": "Three steps, no editing timeline", "template": "flowSteps", "tone": "accent" }
]
}'A scene writes id, startMs, endMs, text (300 characters), emphasis (the
phrase inside text to stress, 60 characters), template, tone
(light, dark, accent), caption (show or none), hidden, visual,
content, params, direction and composed. The body can be a bare array or
wrapped as { "presentationScenes": [ ... ] } ({ "scenes": [ ... ] } is
accepted too).
Unlike caption pages and b-rolls, a presentation scene is rebuilt from what you send rather than layered over the stored one: a recognized key you omit is gone from the saved scene. Read the timeline, edit it, and put the whole thing back.
Timings are validated against the end of the transcript, or the source duration
when there is none. A scene outside that window is clamped, one that ends at or
before it starts is dropped, and scenes are stored sorted by startMs. A video
with neither a transcript nor a known duration cannot place scene timings at all
and is refused with 409 warning-source-not-ready.
POST /videos/{id}/presentation-scenes/generate hands the job back to the AI
director: it re-cuts the presentation from the existing transcript, picking a
template, a tone and a visual for each beat, and replaces the stored timeline
with the result. It charges credits, and it is synchronous but slow, because it
plans the whole film in one pass. The video must already have a transcript.
AI scenes
The scene list of an AI video: one entry per shot, with the prompts that drive its still and its motion, the narration spoken over it, and the media rendered so far. Unlike the other artifacts, scenes are edited one at a time.
| Call | What it does |
|---|---|
POST /videos/{id}/scenes/generate | Plans a whole scene list from the video's prompt. Charges credits and replaces whatever scenes exist |
POST /videos/{id}/scenes | Inserts one empty scene after afterSceneId, or appends when no id is given. Free: nothing is generated yet |
PATCH /videos/{id}/scenes/{sceneId} | Edits imagePrompt, animationPrompt, narration, voiceDescription or duration. Provide at least one |
DELETE /videos/{id}/scenes/{sceneId} | Removes the scene |
POST /videos/{id}/scenes/{sceneId}/image | Generates a new still and attaches it. Charges one image generation |
curl -X PATCH https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/scenes/n1a2b3 \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"narration": "Most founders burn out from never finishing anything.",
"duration": 7
}'duration is 3 to 20 seconds; the prompts and the narration are capped at 2000
characters each and voiceDescription at 300. A newly added scene starts as a
5 second DRAFT with empty prompts, and inherits the preceding scene's
voiceDescription so one character stays consistent. A video holds at most 50
scenes, and a 51st is a 409 limit-reached.
Every editable field is content, so editing, adding, removing a scene or
regenerating its still makes the output stale: videoUrl on the scene and
renderUrl on the video are cleared. Regenerate the still with
POST /videos/{id}/scenes/{sceneId}/image, then
re-render before publishing.
On POST .../image, pass prompt to use a different description for this run;
it is saved as the scene's imagePrompt. Without it the stored imagePrompt is
used, and a scene with neither is a 400. UGC videos reuse one character image
across every scene, so a per-scene regeneration does not apply there and is
refused with 409 warning-invalid-input.
Reference
Videos
Where the artifacts come from, and how to requeue the pipeline that fills them.
Rendering and download
Re-render after every edit, then fetch a URL that resolves.
Credits and limits
What the scene planner, the director and an AI image each charge.
API Reference
Every field of every artifact, with schemas.
Publishing
Connect a rendered video to a publishing profile, pick platforms, and read the publish state including which platforms had no account.
Credits and limits
What each feature charges in credits, the ceilings every plan enforces, and the codes an API call returns when one of them refuses the work.