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.

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.
| Symptom | Cause | What to do |
|---|---|---|
| Same job comes back | Reused Idempotency-Key with the same body | Use a new key per version; a changed body with an old key is 409 idempotency_conflict |
| Warning: short source padded or looped | New clip shorter than the slot duration | Request a longer generation or shorten the slot; the job still succeeds |
| Transition snapped or adjusted | Transition limits (at most 1 s, 50% of the shorter neighbour) vs a short clip | Soft warning in warnings[]; the render still finishes |
| Judder after the swap | Replacement runs at a different frame rate | Set output.fps to one of 24, 25, 30, 60; see output_fps_resamples_sources |
| Audio drifts from picture | Slot durations no longer sum to the spine | Recompute 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
- Listing photos to a narrated tour video with TTS and Timeline
Turn ten listing photos into a 45-second narrated tour: write the script, get word timestamps from TTS, then render stills on a Timeline spine for about $0.15.
- Recast a video longer than 30 seconds: trim, recast, rejoin
H3 Max Recast takes 5 to 30 seconds of source. For a 90 second video on Sume, probe it, trim ranges, recast each at 768p, then plan the join. Cost math inside.
- Review a creator clip's transcript before reusing it as a paid ad
Get a creator clip's transcript for $0.01 per audio minute with video inspect, then flag risky claims with your own word list before the clip becomes an ad.
- Run one video prompt across five Sume models: a Python bake-off
Submit the same prompt to five Sume video models, choose each model's resolution from the catalog, and compare cost and time. Runnable code under 30 lines.
Written by Sume