Reddit 15-second ad: join hook, demo and offer, then plan first

Build a 15-second ad from three clips on Timeline 1.0 and check its length and cost with the unbilled /plan call before you pay for a render.

5 min readSume
All posts

If your best material is spread across several clips, assemble the 15-second Reddit ad with Timeline 1.0 and call POST /v1/timeline-1.0/plan first. The plan call is unbilled: it validates the document, compiles it and returns duration_seconds, segment_count, billable_minutes and estimated_cost_usd_micros, without creating a job or reserving credits. Reddit's 15-second Engaged Video Views option is listed as a public beta from 2026-09-01, with longer videos billing at 15 s (read 2026-10-06), so the length is the number to get right.

Sume facts are from Timeline 1.0: assemble clips into one MP4; the Reddit date and billing rule come from the Social media platform updates, October 2026 (read 2026-10-06). Check Reddit's own bid page for the final definition.

Why assemble instead of trimming one master?

A single trim only works when the first 15 seconds of the master are already the ad. Most masters are not. A common shape is a 3-second problem shot, a 7-second demo and a 5-second offer card, each from a different file. Timeline takes ordered video[] slots plus one audio spine, and returns one MP4. Every source must already be on media.sume.com, so import clips first.

What does the plan call check for you?

The plan is a pure compile. It rejects the mistakes that would fail a paid render later: video[0].start not 0 gives timeline_must_start_at_zero, overlapping slots give segment_overlap, and a fade longer than its neighbours gives transition_too_long. It cannot predict warnings about short sources being padded or looped, so still look at the render's warnings[].

The spine length is the output length: audio.duration_seconds is required, from 1 to 1,800. Set it to 15 and the output is 15 seconds. The last slot's coverage can stop at most 0.5 seconds before the spine ends, so make the slot durations add up to 15 (here 4 + 7 + 4).

import json, os, urllib.request

doc = {
    "audio": {
        "url": "https://media.sume.com/artifacts/artf_demo/voice-15s.wav",
        "duration_seconds": 15,
    },
    "video": [
        {"source_url": "https://media.sume.com/artifacts/artf_demo/problem.mp4",
         "start": 0, "duration": 4},
        {"source_url": "https://media.sume.com/artifacts/artf_demo/demo.mp4",
         "start": 4, "duration": 7,
         "transition": {"type": "fade", "duration": 0.25}},
        {"source_url": "https://media.sume.com/artifacts/artf_demo/offer.mp4",
         "start": 11, "duration": 4},
    ],
}
req = urllib.request.Request(
    "https://api.sume.com/v1/timeline-1.0/plan",
    data=json.dumps(doc).encode(),
    headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
             "Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as r:
    plan = json.load(r)
print(plan["duration_seconds"], plan["estimated_cost_usd_micros"])

Where the voice spine comes from

The audio.url in the document is a single Sume-hosted spine, and audio.parts[] accepts up to 20 gapless slices if you would rather join separate takes; the two cannot be combined. A voiceover from Sume TTS fits here, and a WAV rendering (pcm_s16le) is the safe choice for a spine. If you only want to check the cut before recording the voice, audio.mode: "silence" with a declared duration_seconds lets the plan call price and validate the document with no spine file at all, though fields such as gain_db are refused in that mode (Sume docs: Timeline).

The output defaults to a 1080 by 1920 MP4 and the frame rate follows your longest video source if you do not set output.fps. A mismatch between a source rate and the output rate is reported as output_fps_resamples_sources, so keep the three clips at one frame rate before you assemble them.

What does the render cost?

Timeline is priced at $0.10 per output minute, rounded up, so a 15-second ad is one billable minute: $0.10 at the public rate on the Timeline page. Confirm the live rate in GET /v1/catalog; the plan's estimated_cost_usd_micros gives the same number for your document without charging you. The render itself needs an Idempotency-Key and returns a job; poll GET /v1/jobs/{id}/result for video_url and duration_seconds.

Timeline numbers for a 15-second ad, from Sume's Timeline 1.0 page, read 2026-10-06.
ItemValueNote
Output lengthaudio.duration_seconds = 151 to 1,800 allowed
Slots4 s + 7 s + 4 sStarts 0, 4, 11; first start must be 0
Transitionfade 0.25 s on slot 2No transition on the first slot
Billable minutes1Rounded up per output minute
Plan callUnbilledNo job, no credit hold

What to do with the result

Treat duration_seconds in the render result as the gate. If it is above 15, do not upload it to the Reddit bid. If it is 15, run it through captions (a separate $0.20 job) and attach it. Keep the plan document in your repo next to the ad, because a revision is then a one-line edit to duration or source_in rather than a re-edit in an app.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume