# Upload images and video with the PostEverywhere API **Source:** https://posteverywhere.ai/docs/api/init-media-upload --- [🤖Connect ChatGPT, Claude or any AI agent to manage your social media end to endConnect your AI agent to manage your social media](https://posteverywhere.ai/agents)POST/media/upload # Upload images and video with the PostEverywhere API TWO modes, selected by the request Content-Type. **DIRECT mode (images only, recommended for API clients).** Send `multipart/form-data` with the file in a field named `file` (optional `filename` field to override the name). The upload completes in this single request and the response returns `media_status: "ready"` with `upload_required: false`, no `upload_url`, no `/complete` call. Max 25 MB. Videos sent this way get `415` with instructions. **PRESIGNED mode (all types).** Send file METADATA as JSON. Returns an `upload_url` plus `upload_method` describing how to send the bytes: - images → POST `multipart/form-data`, field name `file` (Cloudflare Images direct upload) - videos (MP4 only) and PDFs → PUT with the declared `Content-Type` (R2 presigned URL) Then you MUST call `POST /media/{media_id}/complete`, or the media stays `uploading` forever otherwise. `expires_at` is authoritative (image URLs last 6 hours, video/PDF URLs 1 hour). Size caps: 20 MB images/PDFs, 500 MB video. Upload quota is only consumed at `/complete`, so retries here are free. **Presigned image caveat**: the image upload host runs an edge bot filter outside our control. Send any custom `User-Agent` header; Python stdlib's default (`Python-urllib/x`) is rejected with HTTP 403 error 1010. `python-requests`, `curl`, node, Go and empty User-Agents all pass. DIRECT mode has no such restriction from any client. Error codes: `validation_error`, `unsupported_media_type`, `file_too_large` (413), `length_required` (411, direct mode), `storage_quota_exceeded` (403), `rate_limit_exceeded`, `service_unavailable`. Guide: [Media requirements by platform](https://posteverywhere.ai/docs/media-requirements) Copy MarkdownCopy for LLMThis endpoint accepts a JSON request body. See the [media guide](https://posteverywhere.ai/docs/media-requirements) for a worked example. ## Responses - 201Presigned mode: an upload ticket (`upload_url` + `upload_method`, then call `/complete`). Direct mode: the finished media, `media_status: "ready"`, `upload_required: false`, `url` set; attach `media_ids` to a post immediately. - 400 - 401 - 402 - 403 - 429 - 500 ## More in Media - [List media](https://posteverywhere.ai/docs/api/list-media) - [Import from URL](https://posteverywhere.ai/docs/api/upload-media-from-url) - [Get media](https://posteverywhere.ai/docs/api/get-media) - [Delete media](https://posteverywhere.ai/docs/api/delete-media) - [Finalise upload](https://posteverywhere.ai/docs/api/complete-media-upload) [← List media](https://posteverywhere.ai/docs/api/list-media)[Import from URL →](https://posteverywhere.ai/docs/api/upload-media-from-url)[← All endpoints](https://posteverywhere.ai/docs/api/reference)