- Home
- Developers
- Media
Media
Uploading images and videos to attach to content
Media uploads use a three-step process: create an upload session, upload the file directly to cloud storage, then complete the upload to register the media item in Maeve Social.
Upload flow
1. POST /v1/workspaces/{workspaceId}/media/upload
2. PUT <presigned uploadUrl>
3. POST /v1/workspaces/{workspaceId}/media/upload/{sessionId}/completeStep 1: Start an upload
curl -X POST https://api.maevesocial.com/v1/workspaces/WORKSPACE_ID/media/upload \
-H "Authorization: Bearer $MAEVE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "photo.png",
"contentType": "image/png",
"fileSize": 102400
}'| Field | Required | Description |
|---|---|---|
filename | Yes | Original filename, max 255 characters |
contentType | Yes | MIME type |
fileSize | Yes | File size in bytes |
Supported content types
| Type | MIME | Max size |
|---|---|---|
| JPEG | image/jpeg | 50 MB |
| PNG | image/png | 50 MB |
| GIF | image/gif | 50 MB |
| WebP | image/webp | 50 MB |
| AVIF | image/avif | 50 MB |
| MP4 | video/mp4 | 512 MB |
| QuickTime | video/quicktime | 512 MB |
Response:
{
"data": {
"sessionId": "session-uuid",
"uploadUrl": "https://storage.example.com/presigned-url...",
"expiresIn": 3600
},
"meta": null
}Step 2: Upload the file bytes
Upload the file bytes directly to the presigned URL. This request goes to cloud storage, not through the Maeve Social API:
curl -X PUT "PRESIGNED_UPLOAD_URL" \
-H "Content-Type: image/png" \
--data-binary @photo.pngStep 3: Complete the upload
curl -X POST https://api.maevesocial.com/v1/workspaces/WORKSPACE_ID/media/upload/SESSION_ID/complete \
-H "Authorization: Bearer $MAEVE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"width": 800,
"height": 600,
"folderId": "folder-uuid"
}'| Field | Required | Description |
|---|---|---|
width | No | Image or video width in pixels |
height | No | Image or video height in pixels |
durationSeconds | No | Video duration in seconds |
thumbnailBase64 | No | Base64-encoded thumbnail image |
folderId | No | Media folder ID |
Response:
{
"data": {
"id": "media-uuid",
"url": "https://media.maevesocial.com/...",
"thumbnailUrl": "https://media.maevesocial.com/.../thumb.jpg",
"folderId": "folder-uuid",
"width": 800,
"height": 600,
"durationSeconds": null
},
"meta": null
}Attaching media to content
Use the media id in a content item's contentMedia array:
{
"integrationId": "integration-uuid",
"intent": "schedule",
"scheduledAt": "2027-01-01T12:00:00Z",
"captions": {
"canonical": "Check out this photo!",
"overrides": {}
},
"contentMedia": [
{
"mediaId": "media-uuid",
"order": 0
}
]
}You can attach up to 10 media items to one content item.
Listing media
Browse your media library with cursor-based pagination:
curl "https://api.maevesocial.com/v1/workspaces/WORKSPACE_ID/media?type=image&sortBy=createdAt&order=desc&limit=20" \
-H "Authorization: Bearer $MAEVE_API_KEY"Query parameters
| Parameter | Default | Options |
|---|---|---|
folderId | none | Folder UUID |
rootOnly | none | true or false |
labelIds | none | Comma-separated media label UUIDs |
isUnlabeled | none | true or false |
type | all | image, video, gif |
search | none | Search by filename |
isFavorite | none | true or false |
isUsed | none | true or false |
isUnused | none | true or false |
state | active | active, deleted, all |
sortBy | createdAt | createdAt, filename, fileSize |
order | desc | asc, desc |
limit | 50 | 1-100 |
cursor | none | Cursor from the previous response's nextCursor |
Response:
{
"data": [
{
"id": "media-uuid",
"url": "https://media.maevesocial.com/...",
"thumbnailUrl": "https://media.maevesocial.com/.../thumb.jpg",
"type": "image/png",
"filename": "photo.png",
"altText": null,
"notes": null,
"fileSize": 102400,
"width": 800,
"height": 600,
"durationSeconds": null,
"folderId": "folder-uuid",
"isFavorite": false,
"isArchived": false,
"deletedAt": null,
"deleteAfter": null,
"usageCount": 0,
"labels": [],
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "cursor-string"
}
}