Upload media
POST/media/upload
Request a presigned upload URL for a media file. This is step 1 of the 3-step upload flow:
POST /v1/media/upload— Get a presigned upload URL (this endpoint). Response contains amedia_idand anext_stepstring telling you exactly what to do next.- Upload your file to the returned
upload_urlusing the method specified inupload_method. POST /v1/media/{media_id}/complete— Signal that the upload is finished. Response includes bothmedia_id(the single UUID you just uploaded) andmedia_ids(a single-element array — convenient for passing straight intoPOST /v1/posts).
For images that are already publicly hosted (CDN, S3 bucket, web search result), use POST /v1/media/upload-from-url instead — one call returns a media_id ready to attach to a post.
Upload methods by type:
- Images — POST multipart-form to the presigned URL (field name:
file) - Videos — PUT to the presigned URL with
Content-Typeheader - Documents — PUT to the presigned URL with
Content-Typeheader
media_id (singular) vs media_ids (plural)media_idis the single UUID string for this one upload — used in URL paths likePOST /v1/media/{media_id}/complete.media_idsis the plural array form used in post requests (POST /v1/posts→"media_ids": ["..."]).
Both are returned from POST /v1/media/upload and POST /v1/media/{media_id}/complete so you don't need to construct the array yourself — just copy media_ids straight into your post payload.
storage_url or url back to the APIStorage URLs and CDN URLs are never part of request payloads. When attaching media to a post, always use media_ids (the array of UUIDs), not URLs. If you send media, media_id (in a request body for POST /v1/posts), mediaId, attachments, or url, the API returns 400 invalid_field_name with a "did you mean media_ids?" hint.
Request Body Schema
POST /media/upload — Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Original filename with extension (max 255 chars). Example: photo.jpg |
content_type | string | Yes | MIME type of the file (see supported types below) |
size | integer | Yes | File size in bytes. Max 20MB for images/documents, 500MB for video. |
width | integer | No | Image/video width in pixels (used for aspect ratio calculation) |
height | integer | No | Image/video height in pixels (used for aspect ratio calculation) |
duration | number | No | Video duration in seconds |
Supported content types
| MIME Type | Category |
|---|---|
image/jpeg | Image |
image/png | Image |
image/gif | Image |
image/webp | Image |
image/heic | Image |
image/heif | Image |
video/mp4 | Video |
application/pdf | Document |
Request Example
{
"filename": "product-photo.jpg",
"content_type": "image/jpeg",
"size": 2048576
}
Response Example
201 — Upload URL generated
{
"data": {
"media_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"media_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"upload_url": "https://upload.posteverywhere.ai/abc123/def456",
"upload_method": {
"method": "POST",
"content_type": "multipart/form-data",
"field_name": "file"
},
"provider": "images",
"expires_in": 3600,
"max_size": 20971520,
"next_step": "Upload your file to upload_url (step 2), then call POST /v1/media/a1b2c3d4-e5f6-7890-abcd-ef1234567890/complete to finalize (step 3)."
},
"error": null,
"meta": {
"request_id": "a1b2c3d4",
"timestamp": "2026-04-10T12:00:00.000Z"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
media_id | string (UUID) | The single UUID for this upload. Use in the URL path of POST /v1/media/{media_id}/complete. |
media_ids | string[] (UUID) | Convenience single-element array — copy straight into a post's media_ids after step 3 completes. |
upload_url | string | Presigned URL to upload your file to |
upload_method.method | string | HTTP method to use: PUT or POST |
upload_method.content_type | string | Content-Type header to set |
upload_method.field_name | string | Form field name (only for POST/multipart uploads) |
upload_method.headers | object | Headers to include with the upload request (for PUT uploads) |
provider | string | Storage provider used for this upload |
expires_in | integer | Seconds until the upload URL expires |
max_size | integer | Maximum file size in bytes |
next_step | string | Human-readable instruction for what to do next (step 2, then step 3). |
Request
Responses
- 201
- 400
- 401
- 429
Upload URL generated
Invalid request parameters
Missing or invalid API key
Rate limit exceeded
Response Headers
Request limit per window
Remaining requests in current window
Unix timestamp when the window resets
Seconds to wait before retrying