Inspect stills at max_edge 960: 540x960 views of a 9:16 ad
Video inspect max_edge 960 returns 9:16 stills at 540x960, TikTok's non-Spark minimum, so you review the ad at the smallest size it may run. 24 stills per call.

Send frames with max_edge 960 and a 9:16 ad comes back as 540x960 stills, which is the minimum size TikTok lists for non-Spark 9:16 ads. The Video inspect default is 768, which gives 432x768 for the same ad, smaller than the TikTok floor. The docs allow max_edge from 64 to 2160, up to 24 stills per call, and billing by Modal compute for the probe and stills (as of 2026-10-08).
Why review at the minimum size
TikTok's page says a 9:16 ad must be at least 540x960 pixels. An ad that is sharp at 1080x1920 can still have small text that is unreadable at 540x960. Reviewing stills at that exact size shows you the worst legal case. The arithmetic is simple: 960 x 9 / 16 = 540, so a 9:16 clip scaled to a 960-pixel long edge is 540 wide.
| max_edge | Still size | Against TikTok 540x960 |
|---|---|---|
| 768 (default) | 432x768 | Below the minimum |
| 960 | 540x960 | Exactly the minimum |
| 1920 | 1080x1920 | Above; the full-size look |
| 2160 | 1215x2160 | Highest the docs allow |
The request
The body needs video_url (a media.sume.com artifact or asset), an Idempotency-Key, and a frames object with either at (1 to 24 timestamps) or fps (above 0, up to 2, capped at 24 stills). It may not have both. Add format jpeg (the default) or png, and max_edge 960. Use seek precise, the default, when the timestamp matters, such as the second a caption appears. Use fast for a quick pass: it moves each still to the keyframe at or before its instant.
For a 45-second ad, a frames object with at set to 1, 5, 10, 20, 30 and 44 gives six stills in a single call. The default mode is sync, which waits up to 30 seconds and returns 202 with a job to poll if it takes longer.
{
"video_url": "https://media.sume.com/artifacts/artf_demo/ad.mp4",
"frames": { "at": [1, 5, 10, 20, 30, 44], "max_edge": 960, "format": "png" }
}What it will not tell you
The probe returns facts about the file, and the stills are samples, so they cannot prove every frame is legible. The page's other limits, 500 MB and 516 kbps, are file-level numbers. This post does not claim that the probe reports bitrate. Check the probe fields in your own result before you build a gate on them.
For a 3-minute Short, the 24-still cap means one still every 7.5 seconds at most, so pick your own timestamps for the moments that matter.
A review routine
Pick six timestamps before you call: the first second, the moment the product appears, each text overlay, and the final frame before the call to action. Send them once at max_edge 960 and open the stills side by side. If any text is unreadable at 540 wide, fix it upstream and re-render rather than re-inspecting. Inspect is billed by Modal compute, with no fixed number in the docs, so batching all six into one call is the sensible way to use it. Use the jpeg default for a quick look and png when you want to zoom into small type.
Sources
Related posts
More in Developers
- One env line picks the video model: $1.25 vs $5.78 per 10 s clip
Read the Sume video model id from one env var. For a 10 s 720p 9:16 clip, gemini-omni-flash-1.1 bills $1.25 and seedance-2.5 bills $5.78.
- Clip-type route table in Python: Sora use cases to Sume models
A 30-line Python route table maps ads, demos and teasers to a Sume model, size and length, refuses a length the model cannot make, and prints the dollar cost.
- Video trim is async by default: mode sync waits 30 s, then poll
Video trim returns a job at once by default. Send mode sync to wait up to 30 s for a 200, else get 202 and poll status, then result. Never resubmit.
- Video trim end past the clip: trim_clamped_to_source and a short ad
If end is beyond the source, Sume video-trim clamps it and warns trim_clamped_to_source. Ask for 0-20 s of a 15 s clip and you get 15 s, which can break a spot.
Written by Sume