One Sume probe, eight platform limits: a Python preflight
Check one video inspect probe against Truth Social, Odysee, ArtStation, Linktree, Spotlight, Reels, TikTok API and Shorts limits in under 30 lines of Python.

Probe the clip once and compare the numbers with a table of rules. Sume video inspect returns a probe with duration_seconds, width, height, rotation, fps, size_bytes, video_codec, has_audio and audio_codec for any clip in your workspace, and you can run it with frames set to false so that no stills are produced. Eight platform rule sets, each taken from that platform's own help or developer page that we read on 2026-10-05, fit in a small Python dictionary.
The point of doing it this way is that the probe is the only expensive step. Everything after it is plain arithmetic on a handful of numbers, so you can run the same check on a folder of clips, in a CI job, or in an agent step that decides whether to trim before it publishes. Because each rule is a line of data with a source, a reviewer can read the table and see where every number came from without reading the code.
The rules and where they come from
Each rule below comes from a page we read. Where a platform gave a limit in minutes or in megabytes, the table converts it to the units the code uses. A blank means the page gave no such limit, and the check skips it.
Two cautions on the table. The Instagram and TikTok rows come from developer reference pages that describe what the API accepts, which can differ from what a person can do in the phone app. And the Shorts row is a help page statement about the format, not an upload validator, so treat vertical and up to 3 minutes as the target and not a guarantee of how the platform classifies the video.
| Platform | Duration | Size | Other |
|---|---|---|---|
| Truth Social | Up to 15 minutes | 450 MB | |
| Odysee | 16 GB | Under 8 Mbps recommended | |
| ArtStation clip, free | Up to 1 minute | 25 MB | |
| Linktree background | No time limit | 50 MB | |
| Snapchat Spotlight | 5 seconds or longer | Post button rule | |
| Instagram Reels API | 3 seconds to 15 minutes | 300 MB | 23 to 60 fps |
| TikTok API | Up to 10 minutes | 4 GB | 23 to 60 fps |
| YouTube Shorts | Up to 3 minutes | Vertical, up to 1080p |
The preflight
The rules are data and the check is one function. That makes it easy to add a ninth platform by adding a line, and easy to audit, since each line maps to a page. The function reads the probe, applies the rotation, and returns a list of problems per platform. An empty list means the clip passes on the numbers that the check covers.
RULES = {
"truth_social": {"max_s": 900, "max_mb": 450},
"odysee": {"max_mb": 16000, "max_mbps": 8},
"artstation_free": {"max_s": 60, "max_mb": 25},
"linktree_bg": {"max_mb": 50}, "spotlight": {"min_s": 5},
"reels_api": {"min_s": 3, "max_s": 900, "max_mb": 300, "fps": (23, 60)},
"tiktok_api": {"max_s": 600, "max_mb": 4000, "fps": (23, 60)},
"shorts": {"max_s": 180, "vertical": True},
}
def preflight(p):
s, mb = p["duration_seconds"], (p.get("size_bytes") or 0) / 1e6
w, h = p["width"], p["height"]
if p.get("rotation") in (90, 270, -90, -270):
w, h = h, w
out = {}
for name, r in RULES.items():
bad = []
if s > r.get("max_s", 1e9): bad.append("too long")
if s < r.get("min_s", 0): bad.append("too short")
if mb > r.get("max_mb", 1e12): bad.append("too big")
if mb * 8 / s > r.get("max_mbps", 1e9): bad.append("bitrate")
if "fps" in r and not r["fps"][0] <= p["fps"] <= r["fps"][1]: bad.append("fps")
if r.get("vertical") and h <= w: bad.append("not vertical")
out[name] = bad
return out
probe = {"duration_seconds": 42.0, "size_bytes": 31_000_000,
"width": 1080, "height": 1920, "rotation": 0, "fps": 30}
print({k: v for k, v in preflight(probe).items() if v})Reading the output
Run the sample and the output is a dictionary of only the failing platforms. For the sample, a 42-second, 31 MB, 1080 by 1920 clip at 30 fps, the free ArtStation rule fails on size, since 31 MB is over 25 MB, and Odysee's 8 Mbps recommendation passes, since 31 MB over 42 seconds is about 5.9 Mbps. The rest pass.
Check that arithmetic yourself, since it is the point of the exercise: 31 times 8 is 248 megabits, and 248 divided by 42 is 5.9 Mbps. So the sample's only failure is ArtStation free by size.
What it leaves out
The preflight does not cover codecs, container details or audio. Odysee's page asks for H264 and AAC, and the Instagram page lists codec and container rules, all of which are in the probe as video_codec, audio_codec and container, but this short version leaves them out to stay under 30 lines. Add them as further keys if you need them.
The preflight also treats size_bytes of null as zero, which lets a clip with no size pass the size rules. In production, treat a null as a failure instead. And all the megabyte figures use 1 MB as 1,000,000 bytes, which is a decision, since the pages do not define the unit.
The usual follow-up is to act on the result. If the failing list is only about length, cut with video trim. If it is about frame rate or size, conform the clip with the same trim job and probe again. The loop ends when the dictionary of failures is empty, and you keep the probe output from the final pass with the file as a record.
Where Sume fits
Sume does the media work, and each platform decides what it accepts. Trim can shorten a clip, conform its width, height and fps with exact precision, or drop audio, and the preflight tells you whether to do that. A trim is $0.02 per job at the public rate.
Sources
- Sume video inspect docs (read 2026-10-05)
- Truth Social photo and video upload limits (read 2026-10-05)
- Odysee uploading and file selection (read 2026-10-05)
- ArtStation how to add video clips (read 2026-10-05)
- Linktree custom image or video background (read 2026-10-05)
- Snapchat help: post Snaps to Spotlight (read 2026-10-05)
- Instagram Graph API: IG User media (Reels requirements) (read 2026-10-05)
- TikTok Content Posting API media transfer guide (read 2026-10-05)
- YouTube Help: Shorts (read 2026-10-05)
Related posts
More in Developers
- Agents SDK blocked_tool_names: hide Sume paid tools from a model
create_static_tool_filter takes allowed and blocked tool names. Use it so an agent on Sume's hosted MCP can read, but never sees a paid generate tool.
- OpenAI gave 184 days to leave the Videos API: a CI catalog check
Notice March 24, removal September 24, 2026, no replacement listed. An 18-line Python check fails CI when a video model id or duration leaves Sume's catalog.
- OpenRouter puts an idempotency key on video webhooks; Sume uses job_id
OpenRouter's video guide adds an idempotency key header to each delivery. Sume dedupes on job_id and takes Idempotency-Key on submit. Which key goes where.
- OpenRouter video callbacks vs Sume job webhooks: what differs
OpenRouter video callback_url reports completed, failed, cancelled, expired. Sume job webhooks send completed, failed, canceled, signed with HMAC-SHA256.
Written by Sume