Re-roll one shot in a stitched film without redoing the rest

Regenerate a single bad shot, swap its source_url in the Timeline 1.0 video array, and re-render the cut for $0.10 per output minute. The other shots stay.

5 min readSume
All posts

To re-roll one shot of a stitched film on Sume, generate only that shot again, then submit the same Timeline 1.0 document with one source_url replaced. You pay for one new generation plus another render at $0.10 per rounded-up output minute. The other shots are separate artifacts and are never regenerated.

That works because every clip is its own job with its own media.sume.com artifact, and a Timeline 1.0 film is a declarative list that points at them.

Why is a re-roll cheap here?

A stitched film is video[] slots over an audio spine. The render compiles ffmpeg on the worker, with no provider inference, so its public rate is $0.10 per output minute (confirm in GET /v1/catalog). A 45-second film re-renders for $0.10. The expensive part of a shot is its generation, and you only repeat that for the shot you dislike.

Compare that with a single-take prompt that asks a model for several shots at once: if shot three fails, you regenerate everything. Per-shot clips trade some continuity risk for the ability to fix one beat. The post on single-take versus stitched clips covers when each is worth it.

How do I keep the timing identical?

Declared start values are authoritative: the compiler compensates for crossfades and never pre-shifts. So if the replacement shot has the same slot duration, every later start stays valid and the audio spine still lines up. If you must change a shot's length, recompute the starts after it, because each must increase and video[0].start must stay 0.

Build start from the durations rather than typing it. The script keeps the shots in a list, replaces one URL, and posts the render with a version-specific Idempotency-Key so the second render is a new job, not a replay of the first.

import os, requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
     "Idempotency-Key": "film-42-render-v2"}
SPINE = "https://media.sume.com/artifacts/artf_demo/voice.wav"
shots = [
    {"url": "https://media.sume.com/artifacts/artf_demo/s1.mp4", "dur": 5},
    {"url": "https://media.sume.com/artifacts/artf_demo/s2.mp4", "dur": 5},
    {"url": "https://media.sume.com/artifacts/artf_demo/s3.mp4", "dur": 5},
]
shots[1]["url"] = "https://media.sume.com/artifacts/artf_demo/s2-take2.mp4"

video, t = [], 0
for i, s in enumerate(shots):
    slot = {"source_url": s["url"], "start": t, "duration": s["dur"]}
    if i:
        slot["transition"] = {"type": "fade", "duration": 0.25}
    video.append(slot)
    t += s["dur"]

body = {"audio": {"url": SPINE, "duration_seconds": t}, "video": video}
r = requests.post("https://api.sume.com/v1/timeline-1.0/render", headers=H, json=body)
r.raise_for_status()
print(r.json()["id"])

What can go wrong on the re-render?

Generating the replacement is an ordinary POST /v1/videos call. Use its own Idempotency-Key, such as film-42-shot-02-take-2, so you can find the job again later and so a network retry cannot bill twice. If you hit queue_full, wait and retry with the same key.

Re-roll checks (Sume docs, read 2026-10-02)
SymptomCauseWhat to do
Same job comes backReused Idempotency-Key with the same bodyUse a new key per version; a changed body with an old key is 409 idempotency_conflict
Warning: short source padded or loopedNew clip shorter than the slot durationRequest a longer generation or shorten the slot; the job still succeeds
Transition snapped or adjustedTransition limits (at most 1 s, 50% of the shorter neighbour) vs a short clipSoft warning in warnings[]; the render still finishes
Judder after the swapReplacement runs at a different frame rateSet output.fps to one of 24, 25, 30, 60; see output_fps_resamples_sources
Audio drifts from pictureSlot durations no longer sum to the spineRecompute starts; coverage may trail the spine by 0.5 s

What does the re-roll not fix?

A swapped shot can still cut badly against its neighbours: a different lighting setup, a face that does not match the previous shot's last frame. The render will not blend that away. Pull frames from the neighbouring clips and compare them (see the post on checking drift with video_frames), and consider generating the replacement from the last frame of the previous shot.

Also keep every take's artifact URL and every render body next to its Idempotency-Key. The docs do not publish a retention period for artifacts, so treat the stored document as your record of what version 1 of the film was, and download finished films you need to keep (sume jobs download <job_id> --output-dir ./out or GET /v1/videos/{jobId}/content).

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume