Upload, download, and manage media attachments programmatically.
List media in your workspace
fileTypestringFilter by type: image, audio, document, lottiepostIdstringFilter by post IDlimitnumberNumber of items (max 100, default 50)cursorstringCursor for pagination (from nextCursor in previous response){
"items": [
{
"id": "att_abc123",
"postId": "pst_def456",
"fileName": "screenshot.png",
"originalFileName": "screenshot.png",
"fileType": "image",
"fileSize": 245760,
"mimeType": "image/png",
"url": "/api/media/uploads/2026/04/01/abc123.png",
"thumbnailUrl": null,
"width": 1920,
"height": 1080,
"duration": null,
"createdAt": 1775073600000
}
],
"hasMore": true,
"nextCursor": "eyJjcmVhdGVkQXQiOjE3NzUwNzM2MDAwMDAsImlkIjoiYXR0X2FiYzEyMyJ9"
}Upload a media file to a post
postIdstringrequiredPost ID to attach the media tofileNamestringrequiredFile name (max 255 chars)mimeTypestringrequiredMIME type (e.g. image/png, audio/mpeg)fileDatastringrequiredBase64-encoded file contentwidthnumberImage width in pixelsheightnumberImage height in pixelsdurationnumberAudio duration in seconds{
"id": "att_abc123",
"postId": "pst_def456",
"fileName": "screenshot.png",
"fileType": "image",
"fileSize": 245760,
"mimeType": "image/png",
"url": "/api/media/uploads/2026/04/01/abc123.png",
"createdAt": 1775073600000,
"author": {
"id": "usr_ghi789",
"name": "Jane Smith",
"email": "jane@example.com",
"image": "/api/media/avatars/jane.jpg"
},
"post": {
"id": "pst_def456",
"title": "Weekly Update"
}
}Get a single media attachment by ID
idstringrequiredMedia attachment ID (URL path)Delete a media attachment
idstringrequiredMedia attachment ID (URL path)The POST /api/v1/media endpoint accepts a JSON body with the file content as a base64-encoded string in the fileData field. Media must be attached to an existing post via the postId field.
Uploads follow the post's live edit permissions. The current API key owner must still be the author of the target post when the request is made, or the upload is rejected.
Media reads follow the post's live visibility too. If you request GET /api/v1/media?postId=... for a post that no longer exists or is no longer visible to the API key owner, the API returns an empty page instead of exposing the attachment list.
imageJPEG, PNG, GIF, WebP, AVIF, HEIC/HEIF, SVG (max 50 MB via API)audioMP3, M4A, WAV, OGG, Opus, FLAC, AAC, AIFF (max 50 MB via API)documentPDF (max 50 MB via API)lottieLottie JSON animations (max 50 MB via API)Video and 3D model uploads are not available via the API due to size constraints. Use the web interface for these file types.
The maximum file size for API uploads is 50 MB (due to the base64 encoding overhead in the JSON body). Files that exceed the limit will receive a 413 response. The web interface supports much larger files (up to 1 GB) via direct-to-R2 uploads.
The list media endpoint uses cursor-based pagination. Pass the nextCursor value from the previous response as the cursor query parameter to fetch the next page. The response includes a hasMore flag to indicate if more results are available.
The cursor is a JSON string containing the last item's createdAt timestamp and attachment ID, which keeps pagination stable when multiple attachments share the same upload time.
Only the post author or a workspace admin/owner can delete media. Deleted files are cleaned up from storage after a 7-day grace period. Media under a legal hold cannot be deleted and will return a 409 response.