Reel end card: trim the last 3 s, then overlay a still
Sume timeline-compose holds a still for the whole clip, so an end card on the last 3 seconds needs a trim first. Trim, compose, then join in Timeline.

To put a follow-me end card on only the last three seconds of a Reel, cut those three seconds into their own clip, overlay the card on that clip, and join it back after the body in Timeline. Sume's timeline compose holds the still for the whole clip it is given: output length always comes from the video layer, and the still can never lengthen it or appear for part of it. So the trick is to make the clip short before composing. It costs three small jobs, $0.02 for the trim, $0.02 for the compose and $0.10 per ceiling minute for the final render.
The three steps
The order matters because compose is flat-priced and capped at 300 seconds, and the end card needs its own clip to be the whole of what it covers.
- Trim:
POST /v1/video-trimwithstartplus exactly one ofendorduration. The output is a new MP4, andprecision: exactis the frame-accurate default. - Compose:
POST /v1/timeline-1.0/composewithoperation: overlay, the card asimage.url, and the short clip asvideo.url. - Join: a Timeline render with the body clip first and the composed ending second.
The first two jobs
The overlay layout takes position (top, center or bottom), width_ratio from 0.05 to 1 and margin_ratio from 0 to 0.45 of height. Keep the card clear of the bottom of the frame, because app buttons and captions sit there; Instagram's reel size page describes the aspect ratios and the cover crop (read 2026-10-03), so check it for the current guidance.
import json, os, urllib.request
API = "https://api.sume.com/v1"
def post(path, body, key):
req = urllib.request.Request(
f"{API}{path}",
data=json.dumps(body).encode(),
headers={
"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": key,
},
method="POST",
)
with urllib.request.urlopen(req) as res:
return json.load(res)
tail = post(
"/video-trim",
{"video_url": os.environ["SUME_CLIP_URL"], "start": 27, "duration": 3},
"end-card-trim-v1",
)
print("trim job", tail["request_id"])
# After the trim job finishes, read its result for video_url, then:
card = post(
"/timeline-1.0/compose",
{
"operation": "overlay",
"image": {"url": os.environ["SUME_CARD_URL"]},
"video": {"url": os.environ["SUME_TAIL_URL"]},
"layout": {"position": "center", "width_ratio": 0.8, "margin_ratio": 0.05},
},
"end-card-compose-v1",
)
print("compose job", card["request_id"])
Costs and limits at a glance
The join step is where the end card lands at the right time. A Timeline render also accepts transitions of up to one second; leave them out if you want a hard cut to the card. Cut the tail from the source file, not from the already-captioned version, or the captions will run under the card.
If the source is a 9:16 vertical clip, set the compose output to a matching width and height (even numbers between 256 and 2160) so the card is not scaled into the wrong frame. A card with transparency is fine, but check that the still probes as a still, or compose refuses it with compose_image_not_still.
| Step | Price | Limit |
|---|---|---|
| video-trim | $0.02 | Output 0.2 to 900 s; source up to 1800 s |
| timeline-compose | $0.02 flat | Up to 300 s |
| timeline render | $0.10 per ceiling minute | Slots up to 200 |
Why not just draw the card in the editor
One more caution: each of the three jobs is asynchronous by default, so wait for the trim result before you read its video_url into the compose call, and wait for the compose result before the final render. A script that fires all three at once will fail on the missing input.
If you edit in Instagram's Edits app or any desktop editor, an end card is a two-click job and you should do it there. The Sume route earns its keep when you are producing many Reels programmatically, for instance a weekly series with the same card, where scripting the three jobs beats opening a project each time.
It also gives you repeatability: the card, the offset and the margins live in code, so a change to the card means re-running the same script rather than redoing each edit by hand. A hard-coded start: 27 is only right for 30-second clips, so compute the start from the clip length when you probe it.
Finally, check the result on a phone. Instagram overlays its own interface on the bottom of a Reel, and a card that looks fine in a preview can be partly covered when played in the app.
Sources
Related posts
More in Use cases
- Open episode 2 on episode 1's last frame: video_frames, frame_images
Pull the closing still with POST /v1/video-frames, then send it as first_frame to POST /v1/videos so the next episode starts where the last cut ended.
- Estimated tax reminder videos for freelancers: an accounting firm plan
The IRS says sole proprietors and others generally pay estimated tax if they expect to owe $1,000. Plan short avatar clips that send clients to the IRS page.
- Eventbrite event video: 24-hour review and a 2:1 cover image
Eventbrite reviews uploaded event video for up to 24 hours and prefers 2:1 images. Build the clip and cover early with Sume so review is not your deadline.
- Exam review Short: show the question, then reveal the answer with cues
A quiz-style study Short in two beats: the question for a few seconds, then the answer. Build it from a still and one Video captions job with timed cues.
Written by Sume