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.

4 min readSume
All posts

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-trim with start plus exactly one of end or duration. The output is a new MP4, and precision: exact is the frame-accurate default.
  • Compose: POST /v1/timeline-1.0/compose with operation: overlay, the card as image.url, and the short clip as video.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.

Jobs in the end-card route, read 2026-10-03
StepPriceLimit
video-trim$0.02Output 0.2 to 900 s; source up to 1800 s
timeline-compose$0.02 flatUp to 300 s
timeline render$0.10 per ceiling minuteSlots 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

All Use cases posts

Written by Sume