Price-match and curbside end card: trim the tail, overlay, join
Add a store-policy end card to a sale clip without re-editing it: trim the last 4 s ($0.02), overlay the card ($0.02), then join in Timeline ($0.10 a minute).

Put a policy end card (price match, curbside pickup, return window) on only the last seconds of a sale clip in three jobs: trim the last 4 seconds ($0.02), overlay your card PNG on that tail ($0.02), then join the untouched start and the carded tail in Timeline 1.0 ($0.10 per started output minute). The compose overlay covers the whole clip it is given, so you shorten the clip first rather than trying to time the card.
Why three steps
Timeline compose puts one still on screen for the entire length of one video, and takes its length from the video. It has no start or end time for the still. To show the card only at the end, hand it only the end. Trimming the tail gives you that, and the source clip is never changed.
This also means the policy card is one small file. When your policy changes (a new price-match window, curbside closed on a day), you re-run the compose and render, not the whole creative.
The three jobs
| Step | Endpoint | Key fields | Rate |
|---|---|---|---|
| Trim the tail | POST /v1/video-trim | video_url, start, duration (0.2-900 s) | $0.02 per job |
| Overlay the card | POST /v1/timeline-1.0/compose | operation overlay, image.url, video.url, layout.position | $0.02 flat per job |
| Join | POST /v1/timeline-1.0/render | audio, video[] slots | $0.10 per started minute |
A runnable chain
The script submits each job, polls it, and feeds the result into the next one. Every URL must be your workspace's media.sume.com artifact or asset, which is why the trim result's video_url can go straight into compose. The idempotency keys carry a version, so a policy change is a new key.
import json, os, time, urllib.request
def call(path, body=None, key=None):
h = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"], "Content-Type": "application/json"}
if key:
h["Idempotency-Key"] = key
data = json.dumps(body).encode() if body else None
return json.load(urllib.request.urlopen(urllib.request.Request("https://api.sume.com" + path, data, h)))
def run(path, body, key):
jid = call(path, body, key)["request_id"]
while call(f"/v1/jobs/{jid}/status")["status"] not in ("completed", "failed", "canceled"):
time.sleep(5)
return call(f"/v1/jobs/{jid}/result")
M = "https://media.sume.com/artifacts/artf_demo/"
tail = run("/v1/video-trim", {"video_url": M + "hero.mp4", "start": 14, "duration": 4}, "ec-trim-v1")
card = run("/v1/timeline-1.0/compose", {"operation": "overlay", "image": {"url": M + "endcard.png"},
"video": {"url": tail["video_url"]}}, "ec-compose-v1")
out = run("/v1/timeline-1.0/render", {"audio": {"mode": "silence", "duration_seconds": 18},
"video": [{"source_url": M + "hero.mp4", "start": 0, "duration": 14},
{"source_url": card["video_url"], "start": 14, "duration": 4}]}, "ec-render-v1")
print(out["video_url"])Check the seam
At the join, the first slot should end exactly where the second starts, and the audio spine must cover the full 18 seconds. A silent spine is declared with audio.mode set to silence. Pull a frame at the join with video frames to confirm there is no jump.
Limits
Stating a price-match or pickup offer is a commitment, and its details belong to your policy page. The card should name the offer and point to the terms, not paraphrase them. If the policy differs by store, make one card per variant. For a single short clip, a plain caption cue (captions, $0.20) is simpler than three jobs. Keep the card legible at phone width, with the offer name large and the terms on the page behind the link, and run a frame check at the first and last second of the card, because the tail is the part viewers who stay to the end will actually remember.
Sources
Related posts
More in Use cases
- Probe a clip before using it as a Seedance 2.5 reference
Before a reference-guided run, check each source clip's length, audio and stills with Sume's video inspect, and transcribe speech at $0.01 a minute.
- Product clip voiceover in 5 languages: 20 seconds, $0.67 on Sume
A silent 20-second product clip voiced in five languages costs up to $0.67 on Sume: about $0.13 each for 300 characters of TTS, a concat and a render.
- Product colorway morph video: Omni first and last frame on Sume
Show a product changing color: send the white shot as first frame and the red shot as last frame to Gemini Omni Flash 1.1. A 5 s clip is $0.63 at 720p.
- Product-drop videos: one bulk queue or a scheduled run per drop?
Use a bulk queue when the drops are known now: up to 100 items, window 1 to 16. Use a schedule when each drop starts on a date. Pick one per series.
Written by Sume