Publishing with Media
Attach media to posts using the
media object in Create Post.
Media fields:
- Images: "media": { "images": ["https://..."] } — one or more image URLs
- Video: "media": { "video": "https://..." } — single video URL, max 300 MB (2 GB for YouTube-only posts)
- PDF carousel: "media": { "carousel": "https://..." } — LinkedIn only
Custom names on LinkedIn (optional):
LinkedIn shows a file name above a PDF carousel and a title below a video. By default these read Shared from Posthero.ai. Override them via the media object — both max 100 characters, LinkedIn only:
- `filename` — the document name shown for a PDF carousel: "media": { "carousel": "https://...", "filename": "My Q3 Playbook" }
- `videoTitle` — the title shown below a video: "media": { "video": "https://...", "videoTitle": "Product demo" }
Set them when creating or updating a post (they aren't part of the upload step). On Update Post, pass an empty string to reset back to the default branding. Plain images have no file name on LinkedIn, so there's nothing to set there.
Where to get media URLs:
Option A — Use any publicly accessible HTTPS URL. No upload step needed. Works for all platforms except TikTok (TikTok requires URLs hosted on our domain).
Option B — Upload the file to PostHero. Use the Upload Media endpoint. It accepts images, videos, and PDFs up to 100 MB. Returns a hosted URL ready to use.
Video size limits:
- 300 MB for posts to any platform other than YouTube, and for posts that mix YouTube with other platforms.
- 2 GB for posts that go only to YouTube. Pass the video as your own HTTPS URL (Option A); files over 100 MB can't go through Upload Media. PostHero downloads the video from your URL at publish time and sends it straight to YouTube without storing a copy.
A video URL over the limit is rejected with 400 VALIDATION_ERROR when you create or update the post. If its size can't be checked then, the post fails at publish time instead. The platform limits below may be higher, but these are the largest videos PostHero publishes.
Auto-processing: PostHero automatically compresses or converts images that exceed a platform's size limit before publishing. Threads images over 8 MB are compressed to JPEG. TikTok images are resized to 1080px and converted to JPEG if needed. This avoids publish failures but may reduce image quality — for best results, stay within the limits below.
Platform media limits| Platform | Images | Video | Notes |
|---|---|---|---|
| JPG, PNG, GIF · up to 9 · max 5 MB each | MP4 · max 5 GB · 3 sec – 10 min | PDF carousel via media.carousel (up to 300 pages, max 100 MB) | |
| twitter/x | JPG, PNG, GIF, WebP · up to 4 · max 5 MB each (GIF: max 15 MB) | MP4 · max 512 MB · max 140 sec | |
| threads | JPG, PNG · up to 10 · max 8 MB each | MP4 · max 100 MB · max 5 min | Images over 8 MB are auto-compressed to JPEG before publishing |
| JPG, PNG · up to 10 in carousel · max 8 MB each | MP4 · max 1 GB · 3–90 sec (Reels) | contentType controls feed / reel / story / carousel | |
| bluesky | JPG, PNG, WebP, GIF · up to 4 · max 1 MB each | — | |
| tiktok | JPEG, WebP · up to 35 · max 20 MB · max 1080px | MP4 · max 4 GB (PostHero: 300 MB) | Images auto-converted to JPEG and resized if they exceed limits. Carousels require URLs from Upload Media endpoint. |
| JPG, PNG · max 4 MB each | MP4 · max 4 GB · max 240 min | ||
| youtube | Optional custom thumbnail via platformContent.youtube.thumbnail · JPG/PNG/GIF · ≤30 MB (auto-compressed to YouTube's 2 MB limit) · 1280×720 recommended | MP4 · max 256 GB / 12 hrs (PostHero: 2 GB via your own URL) | Requires title via platformContent.youtube.title. Custom thumbnails require a verified channel and are ignored on Shorts. |
Example request
// Step 1: Upload
curl --request POST \
--url https://server.posthero.ai/api/v1/media/upload \
--header 'Authorization: Bearer YOUR_API_KEY' \
--form 'file=@/path/to/image.png'
// Response: { "data": { "url": "https://s3.amazonaws.com/..." } }
// Step 2: Create post with the uploaded image
curl --request POST \
--url https://server.posthero.ai/api/v1/posts \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"text": "Check this out!",
"platforms": [{ "platform": "linkedin", "accountId": "abc123" }],
"media": { "images": ["https://s3.amazonaws.com/..."] },
"publishNow": true
}'
// Or publish a PDF carousel with a custom LinkedIn file name
curl --request POST \
--url https://server.posthero.ai/api/v1/posts \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"text": "My latest playbook 👇",
"platforms": [{ "platform": "linkedin", "accountId": "abc123" }],
"media": { "carousel": "https://s3.amazonaws.com/...pdf", "filename": "My Q3 Playbook" },
"publishNow": true
}'