Python SDK

Media

Upload images, videos, and documents with the Late Python SDK

The Media resource handles file uploads for images, videos, and documents. The SDK provides two upload methods depending on file size.

Upload Methods Overview

MethodFile SizeStorageToken Required
Direct Upload≤ 4 MBLate APIAPI Key only
Large File Upload4 MB - 500 MBVercel BlobVercel Token

Direct Upload (Small Files)

For files up to 4 MB, use the direct upload methods. These upload directly to the Late API.

Upload Single File

from late import Late

client = Late(api_key="your_api_key")

# Upload a single image
response = client.media.upload("photo.jpg")

print(response.files[0].url)
print(response.files[0].filename)
print(response.files[0].size)
print(response.files[0].mimeType)

Upload Multiple Files

# Upload several files at once
response = client.media.upload_multiple([
    "image1.jpg",
    "image2.png",
    "thumbnail.webp"
])

# Access each uploaded file
for file in response.files:
    print(f"{file.filename}: {file.url}")

Upload from Bytes

Useful when you have file content in memory (e.g., from a download or generation):

# Upload from bytes
image_bytes = download_image_from_somewhere()

result = client.media.upload_bytes(
    content=image_bytes,
    filename="generated.png",
    mime_type="image/png"  # optional, auto-detected from filename
)

Large File Upload (Vercel Blob)

For files larger than 4 MB (up to 500 MB), use the Vercel Blob upload methods. This requires a Vercel Blob token.

Getting a Vercel Token

  1. Go to Vercel Dashboard → Storage → Create Database → Blob
  2. Create a new Blob store
  3. Go to the store settings and copy the BLOB_READ_WRITE_TOKEN

Upload Large File

# Upload a large video file
response = client.media.upload_large(
    "video.mp4",
    vercel_token="vercel_blob_rw_xxxxx"
)

print(response.url)
print(response.pathname)
print(response.contentType)
print(response.size)
print(response.downloadUrl)

Progress Tracking

Monitor upload progress for large files:

from late.upload import UploadProgress

def on_progress(progress: UploadProgress):
    print(f"Uploading: {progress.percentage:.1f}% ({progress.uploaded_bytes}/{progress.total_bytes} bytes)")

result = client.media.upload_large(
    "large_video.mp4",
    vercel_token="vercel_blob_rw_xxxxx",
    on_progress=on_progress
)

Upload Large Bytes

# Upload large content from bytes
video_bytes = get_video_bytes()

result = client.media.upload_large_bytes(
    content=video_bytes,
    filename="video.mp4",
    vercel_token="vercel_blob_rw_xxxxx",
    mime_type="video/mp4"
)

Upload Token Flow (Browser-Based)

For scenarios where direct file upload isn't possible (e.g., AI assistants, chatbots), use the upload token flow:

# 1. Generate an upload token
token_response = client.media.generate_upload_token()

print(f"Ask user to upload at: {token_response.uploadUrl}")
# User opens the URL in their browser and uploads files

# 2. Check token status and get uploaded files
status_response = client.media.check_upload_token(token_response.token)

if status_response.status.value == "completed":
    for file in status_response.files:
        print(f"Uploaded: {file.url}")
elif status_response.status.value == "pending":
    print("Still waiting for upload...")
elif status_response.status.value == "expired":
    print("Token expired, generate a new one")

Async Methods

All upload methods have async versions:

import asyncio
from late import Late

async def upload_files():
    async with Late(api_key="your_api_key") as client:
        # Direct upload
        result = await client.media.aupload("photo.jpg")

        # Multiple files
        result = await client.media.aupload_multiple(["a.jpg", "b.jpg"])

        # From bytes
        result = await client.media.aupload_bytes(content, "file.png")

        # Large files
        result = await client.media.aupload_large(
            "video.mp4",
            vercel_token="vercel_blob_rw_xxxxx"
        )

        # Upload token
        token = await client.media.agenerate_upload_token()
        status = await client.media.acheck_upload_token(token["token"])

asyncio.run(upload_files())

Supported File Types

Images

FormatExtensionsMIME Type
JPEG.jpg, .jpegimage/jpeg
PNG.pngimage/png
WebP.webpimage/webp
GIF.gifimage/gif

Videos

FormatExtensionsMIME Type
MP4.mp4video/mp4
QuickTime.movvideo/quicktime
AVI.avivideo/x-msvideo
WebM.webmvideo/webm
M4V.m4vvideo/x-m4v

Documents

FormatExtensionsMIME Type
PDF.pdfapplication/pdf

Error Handling

from late.upload import LargeFileError
from late.client.exceptions import LateAPIError

try:
    # This will raise LargeFileError if file > 4MB
    result = client.media.upload("large_video.mp4")
except LargeFileError as e:
    print(f"File too large ({e.size} bytes). Use upload_large() instead.")
    result = client.media.upload_large(
        "large_video.mp4",
        vercel_token="vercel_blob_rw_xxxxx"
    )
except LateAPIError as e:
    print(f"Upload failed: {e.message}")

Using Uploaded Media in Posts

Once uploaded, use the URL in your posts:

from datetime import datetime, timedelta
from late import Platform, MediaType

# Upload media
media_result = client.media.upload("product.jpg")
media_url = media_result.files[0].url

# Create post with media
post = client.posts.create(
    content="Check out our new product!",
    platforms=[{"platform": Platform.TWITTER, "accountId": "acc_123"}],
    media_items=[{"type": MediaType.IMAGE, "url": media_url}],
    scheduled_for=datetime.now() + timedelta(hours=1)
)

API Reference

media.upload()

Upload a single file (max 4 MB).

ParameterTypeRequiredDescription
file_pathstr | PathYesPath to the file to upload

Returns: MediaUploadResponse

Raises: LargeFileError if file exceeds 4 MB.

media.upload_multiple()

Upload multiple files at once (each max 4 MB).

ParameterTypeRequiredDescription
file_pathslist[str | Path]YesList of file paths to upload

Returns: MediaUploadResponse

media.upload_bytes()

Upload from bytes (max 4 MB).

ParameterTypeRequiredDescription
contentbytesYesFile content as bytes
filenamestrYesName for the file
mime_typestrNoMIME type (auto-detected from filename)

Returns: MediaUploadResponse

media.upload_large()

Upload large file using Vercel Blob (up to 500 MB).

ParameterTypeRequiredDescription
file_pathstr | PathYesPath to the file to upload
vercel_tokenstrYesVercel Blob token (vercel_blob_rw_xxx)
on_progressCallable[[UploadProgress], None]NoProgress callback

Returns: MediaLargeUploadResponse

media.upload_large_bytes()

Upload large content from bytes using Vercel Blob.

ParameterTypeRequiredDescription
contentbytesYesFile content as bytes
filenamestrYesName for the file
vercel_tokenstrYesVercel Blob token
mime_typestrNoMIME type
on_progressCallable[[UploadProgress], None]NoProgress callback

Returns: MediaLargeUploadResponse

media.generate_upload_token()

Generate an upload token for browser-based uploads.

Returns: UploadTokenResponse

media.check_upload_token()

Check status of an upload token.

ParameterTypeRequiredDescription
tokenstrYesThe upload token

Returns: UploadTokenStatusResponse

Best Practices

  1. Choose the right method: Use direct upload for small files (< 4MB), Vercel Blob for larger files
  2. Track progress: For large uploads, use the on_progress callback to provide user feedback
  3. Handle errors: Always handle LargeFileError to gracefully switch to large file upload
  4. Validate before upload: Check file size and type before uploading to avoid errors
  5. Use async for multiple files: When uploading many files, use async methods for better performance