Skip to content

Media Uploads

How to upload images, videos, and documents for use in posts

Posts with media perform better on every platform. Zernio uses presigned URLs for fast, direct uploads up to 5GB.

Upload Flow

  1. Request a presigned URL from POST /v1/media/presign
  2. Upload the file directly to the returned uploadUrl using a PUT request
  3. Use the publicUrl in your post's mediaItems array

Step 1: Get a Presigned URL

typescript
const { uploadUrl, publicUrl } = await zernio.media.getMediaPresignedUrl({
  fileName: 'photo.jpg',
  fileType: 'image/jpeg'
});
python
result = client.media.get_media_presigned_url(
    filename="photo.jpg",
    content_type="image/jpeg"
)
upload_url = result["upload_url"]
public_url = result["public_url"]
bash
curl -X POST "https://zernio.com/api/v1/media/presign" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fileName": "photo.jpg",
    "fileType": "image/jpeg"
  }'

Response:

json
{
  "uploadUrl": "https://storage.googleapis.com/...",
  "publicUrl": "https://storage.googleapis.com/...",
  "expires": "2024-01-15T11:00:00.000Z"
}

Step 2: Upload the File

Upload directly to the presigned URL (no auth header needed):

typescript
// Upload directly to the presigned URL (no auth needed)
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'image/jpeg' },
  body: fileBuffer
});
python
import httpx

# Upload directly to the presigned URL (no auth needed)
with open("photo.jpg", "rb") as f:
    httpx.put(upload_url, content=f.read(), headers={"Content-Type": "image/jpeg"})
bash
curl -X PUT "UPLOAD_URL_FROM_STEP_1" \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg

Step 3: Use in a Post

Include the publicUrl in your post:

typescript
const { post } = await zernio.posts.createPost({
  content: 'Check out this photo!',
  mediaItems: [
    { url: publicUrl, type: 'image' }
  ],
  platforms: [
    { platform: 'twitter', accountId: 'acc_xyz789' }
  ]
});
python
result = client.posts.create_post(
    content="Check out this photo!",
    media_items=[
        {"url": public_url, "type": "image"}
    ],
    platforms=[
        {"platform": "twitter", "accountId": "acc_xyz789"}
    ]
)
bash
curl -X POST "https://zernio.com/api/v1/posts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Check out this photo!",
    "mediaItems": [
      { "url": "PUBLIC_URL_FROM_STEP_1", "type": "image" }
    ],
    "platforms": [
      { "platform": "twitter", "accountId": "acc_xyz789" }
    ]
  }'

See the Presigned Upload endpoint for full parameter details.

Supported Formats

TypeFormatsMax Size
ImagesJPG, PNG, GIF, WebP5 GB
VideosMP4, MOV, AVI, WebM5 GB
DocumentsPDF (LinkedIn only)100 MB

Platform-Specific Media Rules

Each platform has its own requirements for media. Here's a quick reference:

PlatformMax ImagesMax VideosNotes
Twitter41No mixing images and videos
Instagram10 (carousel)1 (Reel)Stories: single image/video
FacebookMultiple1Stories: single image/video
LinkedIn20 images1Single PDF supported (max 300 pages)
TikTok35 photos1No mixing photos and videos
YouTube-1 (required)Optional custom thumbnail
Pinterest11One image or one video per Pin
Bluesky41Images auto-compressed to ~1MB
Threads10 images1No video carousels
Snapchat11Required for all post types

For detailed platform requirements, see the Platforms section or the Create Post endpoint.

Auto-Compression

Some platforms have strict file size limits. Zernio handles this automatically:

  • Bluesky: Images are automatically recompressed to stay under Bluesky's ~1MB blob limit
  • YouTube Thumbnails: Custom thumbnails via MediaItem.thumbnail are processed to meet YouTube's requirements

Custom Media Per Platform

You can use different media for different platforms in the same post using customMedia in the platform entry:

json
{
  "content": "Same text, different media per platform",
  "mediaItems": [{ "url": "default-image.jpg", "type": "image" }],
  "platforms": [
    { "platform": "twitter", "accountId": "acc_1" },
    {
      "platform": "instagram",
      "accountId": "acc_2",
      "customMedia": [{ "url": "square-image.jpg", "type": "image" }]
    }
  ]
}