LinkedIn video ad file check in Python before initializeUpload

Check an MP4 against LinkedIn's Videos API range of 75kb to 500MB before you call initializeUpload, and print the fileSizeBytes the request needs.

5 min readSume
All posts

Before you call LinkedIn's initializeUpload, check the file locally: it must be an MP4, between 75kb and 500MB per the Videos API page (read 2026-10-06), and the request needs its exact byte size as fileSizeBytes. The script below does that with the standard library and no network. It is useful as the last step after a Sume render or trim, because those jobs return a URL and the upload step needs a local file.

Source: LinkedIn Videos API, Microsoft Learn (read 2026-10-06). The page does not say whether kb and MB are decimal or binary, so the script treats 500MB as 500,000,000 bytes, the stricter reading, and tells you when a file sits between the two.

What LinkedIn asks for

initializeUploadRequest takes owner (a person or organization URN), fileSizeBytes, and optional uploadCaptions and uploadThumbnail booleans. The response has uploadInstructions, each with a firstByte, lastByte and uploadUrl; the first byte range is 0 to 4194303 and the next starts at 4194304, so each part is 4 MB. The same page gives 5GB as the maximum for the Videos size, but the video file range quoted above is lower, so use that one for ads.

The check

The script reads a path, rejects anything not ending in .mp4, compares the size against the bounds and prints the part count the upload will need. A part count is ceil(size / 4194304). A file between 500,000,000 and 524,288,000 bytes gets a warning rather than a pass.

import math, os, sys

PART = 4194304
LOW_DEC = 75_000
HIGH_DEC, HIGH_BIN = 500_000_000, 500 * 1024 * 1024

def check(path):
    if not path.lower().endswith(".mp4"):
        return "reject: not an .mp4"
    size = os.path.getsize(path)
    if size < LOW_DEC:
        return f"reject: {size} bytes is under the 75kb floor"
    if size > HIGH_BIN:
        return f"reject: {size} bytes is over 500MB"
    note = " (between decimal and binary 500MB, risky)" if size > HIGH_DEC else ""
    parts = math.ceil(size / PART)
    return f"ok: fileSizeBytes={size}, parts={parts}{note}"

if __name__ == "__main__":
    print(check(sys.argv[1] if len(sys.argv) > 1 else __file__))

Why not just let LinkedIn refuse it?

A refusal costs a round trip and, worse, a half-finished upload session. The video's status can come back PROCESSING_FAILED with a processingFailureReason after you have uploaded every part, which wastes the upload time. A local check is free. It also catches the case that matters most for generated video: a render that is fine for your player but huge because you asked for 4K when 1080p would do.

Upload facts from LinkedIn's Videos API page, read 2026-10-06.
ItemValueWhere it matters
FormatMP4Reject other extensions
Size range75kb to 500MBCheck both bounds
Part size4 MB (first range 0 to 4194303)Count parts from fileSizeBytes
CaptionsOne file, English onlyFor ads it must process to serve
StatusPROCESSING, PROCESSING_FAILED, AVAILABLE, WAITING_UPLOADPoll after finalizeUpload

Where Sume fits

Make the file with the surfaces that give you control of size: a timeline render lets you set output.width, output.height and output.fps, and trim can conform them on an exact cut. Download the result, run the check, then upload. The stored post on LinkedIn's 4 MB parts and ETags walks through the finalize step. For the render options see Timeline 1.0: assemble clips into one MP4, and for the cut see Video trim: cut a range from one Sume-hosted clip.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume