Upload a file directly
Uploads a file in the request itself and returns a public URL, for cases where a two-step presign is inconvenient and the file is small — chiefly direct message attachments, where Meta fetches the URL itself. The stored object is deleted automatically after seven days, so it is not a substitute for POST /v1/media/presign when publishing posts. Maximum 25MB. Requires a read-write API key.
Authorization
bearerAuth PostZen API key.
In: header
Request Body
multipart/form-data
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/media/upload-direct" \ -F file="string"{ "url": "https://media.postzen.dev/direct-uploads/0001787068800000-6f0d0296-6a1c-4d5b-9a2e-3f8c1b7d4e90/receipt.jpg", "filename": "receipt.jpg", "contentType": "image/jpeg", "size": 184320}{ "error": "JSON body is required"}{ "error": "Unauthorized"}{ "error": "API key requires read_write permission"}{ "error": "rate_limited", "retryAfter": 30}{ "error": "Failed to create post"}Create a presigned media upload URL POST
Creates a presigned URL for uploading an image, video, GIF, or PDF to PostZen-hosted storage. Upload the file with an HTTP `PUT` to `uploadUrl`, then reference `publicUrl` in post `mediaItems`. This endpoint requires a read-write API key.
Bulk upload posts from CSV POST
Validates and creates up to 500 posts from a CSV file. This endpoint requires a read-write API key. Each data row targets every connected account for the selected platforms on one profile. Set `dryRun=true` to validate without billing checks, media ingestion, or writes. A mixed success/failure response uses HTTP 207; all-success and all-failure responses use HTTP 200. | CSV column | Purpose | | --- | --- | | `post_content` | Required base post text. | | `platforms` | Required comma-separated platforms: `instagram`, `facebook`, `threads`, `tiktok`, `linkedin`, `x`, `youtube`, `pinterest`, `bluesky`, or `telegram`; `twitter` aliases `x`. | | `profiles` | Required single profile id or unique profile name. | | `schedule_time` | Required column. Use `YYYY-MM-DD HH:mm[:ss]` in `tz`, or ISO 8601 with an explicit offset. May be empty for draft, publish-now, or queue rows. | | `tz` | IANA timezone; defaults to `UTC`. | | `media_urls` | Comma-separated HTTP(S) URLs, up to 10 per row and 50 distinct URLs per upload. | | `is_draft`, `publish_now`, `use_queue` | Mutually exclusive boolean mode flags. With none set, the row is scheduled. | | `title`, `tags`, `hashtags`, `mentions`, `visibility` | General title, comma-separated tags, appended hashtags/mentions, and YouTube visibility. | | `custom_content_<platform>` | Platform-specific content override; `custom_content_twitter` targets X. | | `youtube_title`, `youtube_description` | YouTube title and description override. | | `facebook_first_comment`, `linkedin_first_comment` | First comments. | | `instagram_content_type`, `instagram_collaborators`, `instagram_first_comment` | Instagram post type, collaborators, and first comment. | | `tiktok_privacy`, `tiktok_allow_comments`, `tiktok_allow_duet`, `tiktok_allow_stitch`, `tiktok_brand_partner`, `tiktok_organic_brand`, `tiktok_draft`, `tiktok_description` | TikTok publishing options. | | `telegram_parse_mode`, `telegram_disable_web_page_preview`, `telegram_disable_notification`, `telegram_protect_content` | Telegram publishing options. | | `pinterest_title`, `pinterest_link`, `pinterest_board_id` | Pinterest pin options. |