Upload Photos
Upload photos (and mixed media for supported platforms) to various social media platforms using this endpoint.
Endpoint
POST /api/upload_photos
Headers
| Name | Value | Description |
|---|---|---|
| Authorization | Apikey your-api-key-here | Your API key for authentication |
Common Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| user | String | Yes | User identifier |
| platform[] | Array | Yes | Platform(s) to upload to. Supported values: tiktok, instagram, linkedin, facebook, x, threads, pinterest, bluesky |
| photos[] | Array | Yes | Array of files to upload. Accepts photos (jpg, png, etc.). Note: You can also include videos (mp4, mov, etc.) ONLY for Instagram and Threads mixed carousels. |
| title | String | Yes | Default title/caption of the post |
| description | String | No | Optional extended text used on TikTok photo descriptions, LinkedIn commentary, Facebook descriptions, Pinterest notes, and Reddit bodies. Ignored elsewhere. |
| scheduled_date | String (ISO-8601) | No | Optional date/time (ISO-8601) to schedule publishing, e.g., "2024-12-31T23:45:00Z". Must be in the future (≤ 365 days). Omit for immediate upload. |
| async_upload | Boolean | No | If true, the request returns immediately with a request_id and processes in the background. See Upload Status. |
| first_comment | String | No | Automatically post a first comment after publishing. Supported on Instagram, LinkedIn, Facebook, and Bluesky. On X (Twitter) and Threads, this creates a reply to the main post. For X threads, the comment is posted as a reply to the last tweet in the thread. |
Important: If you set
async_uploadtofalsebut the upload takes longer than 59 seconds, it will automatically switch to asynchronous processing to avoid timeouts. In that case, use therequest_idwith the Upload Status endpoint to check the upload status and result.
Scheduling behavior: When you provide
scheduled_date, the API responds with202 Acceptedand includes ajob_id. That samejob_idwill later appear in Upload History to correlate the scheduled job with the publish record.
Video Support (Mixed Carousels):
- Instagram & Threads: You can upload videos in the
photos[]array to create mixed carousels (photos + videos).- All other platforms (Facebook, TikTok, LinkedIn, X, Pinterest): Do NOT upload videos to this endpoint. Use the Upload Video endpoint instead. Uploading videos here for these platforms will result in an error.
Platform-Specific Titles
The title parameter serves as a fallback. To set a custom title for a particular platform, use the optional [platform]_title parameter. If provided, it will override the main title for that platform.
Example Optional Parameters:
instagram_title: "Check out my latest reel on Instagram! #reels"facebook_title: "Excited to share this new video with my Facebook friends and family."tiktok_title: "New TikTok video just dropped! 🔥"linkedin_title: "A professional insight on the latest industry trends, discussed in this video."x_title: "New video out now! 📢"
Platform-Specific Parameters
LinkedIn
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| linkedin_title | String | No | Specific title for the LinkedIn post. Fallbacks to title. | title |
| linkedin_description or description | String | No | Sent as the post commentary. If omitted, we reuse title. | title |
| visibility | String | No | Visibility setting for the post (accepted value: "PUBLIC") | PUBLIC |
| target_linkedin_page_id | String | No | LinkedIn page ID to upload photos to an organization | "107579166" |
Facebook
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| facebook_title | String | No | Specific title for the Facebook post. Fallbacks to title. | title |
| facebook_page_id | String | Yes | Facebook Page ID where the photos will be posted | - |
| facebook_media_type | String | No | Type of media ("POSTS" or "STORIES") | "POSTS" |
Note: The caption is applied only to the first photo uploaded. For correct posting on Facebook, ensure the Page is directly associated with your personal profile and not managed through a Business Portfolio.
Note: If
facebook_page_idis not provided, we will automatically use the user's only connected Page (if exactly one exists). If multiple Pages are connected, the API returns a helpful error with anavailable_pageslist so you can choose one. Posting to personal Facebook profiles via API is not supported by Meta; only Pages can be posted to.
X (Twitter)
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| x_title | String | No | Specific title for the tweet. Fallbacks to title. | title |
| x_long_text_as_post | Boolean | No | When true, publishes long text as a single post. Otherwise, creates a thread. | false |
| reply_settings | String | No | Controls who can reply to the tweet ("following", "mentionedUsers", "subscribers", "verified") | - |
| geo_place_id | String | No | Place ID for adding geographic location to the tweet | - |
| nullcast | Boolean | No | Whether to publish without broadcasting (promotional/promoted-only posts) | false |
| for_super_followers_only | Boolean | No | Tweet exclusive for super followers | false |
| community_id | String | No | Community ID for posting to specific communities | - |
| share_with_followers | Boolean | No | Share community post with followers | false |
| direct_message_deep_link | String | No | Link to take the conversation from public timeline to private Direct Message | - |
| tagged_user_ids | Array | No | Array of user IDs to tag in the photos (max 10 users) | [] |
| reply_to_id | String | No | ID of the tweet to reply to. Creates a reply to the specified tweet. | - |
| exclude_reply_user_ids | Array | No | Array of user IDs to exclude from replying to this tweet. Requires reply_to_id. | [] |
Note: For Twitter uploads, specify the platform as "x" in the platform[] array.
The global description field is ignored for X photo uploads.
How X (Twitter) Thread Creation Works (Advanced Logic)
Note: The following describes the default thread creation logic. To override this and post long text as a single post, set the x_long_text_as_post parameter to true.
The system is engineered to create well-formatted, natural-looking threads on X (formerly Twitter). Instead of simply splitting text at every line break, it intelligently groups paragraphs to create more readable tweets.
Here's the step-by-step logic:
Intelligent Paragraph Grouping (Primary Method):
The function first identifies distinct paragraphs (any text separated by a blank line).
It then combines as many of these paragraphs as possible into a single tweet, filling it up to the 280-character limit without exceeding it. The double newline (\n\n) between combined paragraphs is preserved for formatting.
This results in fewer, more substantial tweets that flow naturally, just as if a person had written them.
Handling Exceptionally Long Paragraphs:
If a single paragraph is, by itself, longer than the 280-character limit, a more granular splitting logic is automatically triggered for that paragraph only:
- Split by Line Break: The system first attempts to break the paragraph down by its individual line breaks (
\n). - Split by Word: If any of those single lines are still too long, it will split them by words as a final resort.
Media Attachment:
For posts that include photos or videos, all media is attached only to the first tweet of the thread. The subsequent tweets in the thread will be text-only replies.
TikTok
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| tiktok_title | String | No | Specific title for the TikTok post. Fallbacks to title. | title |
| post_mode | String | No | Controls how the upload is handled. DIRECT_POST publishes immediately; MEDIA_UPLOAD sends the media to the TikTok inbox so users can finish editing in-app. | DIRECT_POST |
| privacy_level | String | No | Accepted values: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY. | PUBLIC_TO_EVERYONE |
| auto_add_music | Boolean | No | Automatically add background music to photos | false |
| disable_comment | Boolean | No | Disable comments on the post | false |
| brand_content_toggle | Boolean | No | Set to true for paid partnerships that promote third-party brands. | false |
| brand_organic_toggle | Boolean | No | Set to true when promoting the creator's own business. | false |
| photo_cover_index | Integer | No | Index (starting at 0) of the photo to use as the cover/thumbnail for the TikTok photo post | 0 |
| tiktok_description or description | String | No | For photo posts, used as description inside post_info. | title |
Instagram
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| instagram_title | String | No | Specific title for the Instagram post. Fallbacks to title. | title |
| media_type | String | No | Type of media ("IMAGE" or "STORIES"). Automatically handles CAROUSEL/REELS logic if mixed media is detected. | "IMAGE" |
The global description field is ignored for Instagram uploads (title serves as caption).
Threads
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| threads_title | String | No | Specific title for the Threads post. Fallbacks to title. | title |
The global description field is ignored for Threads photo uploads.
Pinterest
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| pinterest_title | String | No | Specific title for the Pinterest Pin. Fallbacks to title. | title |
| pinterest_description or description | String | No | Populates the Pin description. If omitted, we reuse title. | title |
| pinterest_board_id | String | Yes | Pinterest board ID to publish the photo to. | - |
| pinterest_alt_text | String | No | Alt text for the image. | - |
| pinterest_link | String | No | Destination link for the photo Pin. | - |
Bluesky
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
| bluesky_title | String | No | Specific text for the Bluesky post. Fallbacks to title. | title |
Note: Bluesky supports up to 4 images per post.
Example Requests
Upload Photo and Video to Instagram (Carousel)
curl \
-H 'Authorization: Apikey your-api-key-here' \
-F 'photos[]=@/path/to/image.jpg' \
-F 'photos[]=@/path/to/video.mp4' \
-F 'user="test"' \
-F 'platform[]=instagram' \
-F 'title="My Mixed Carousel"' \
-X POST https://api.upload-post.com/api/upload_photos
Upload Photos to Facebook
curl \
-H 'Authorization: Apikey your-api-key-here' \
-F 'photos[]=@/path/to/image1.jpg' \
-F 'photos[]=@/path/to/image2.jpg' \
-F 'user="test"' \
-F 'platform[]=facebook' \
-F 'facebook_page_id="123456789"' \
-F 'title="My Photo Album"' \
-X POST https://api.upload-post.com/api/upload_photos
Responses
- 200 OK (synchronous, finished fast)
{
"success": true,
"results": {
"instagram": { "success": true, "url": "https://instagram.com/p/...", "photos_were_processed": true, "changes_per_image": [ {} ] },
"reddit": { "success": false, "error": "Subreddit is required for photo posts to Reddit." }
},
"usage": { "count": 13, "limit": 100, "last_reset": "..." }
}
- 200 OK (asynchronous/background started or sync→background fallback)
{
"success": true,
"message": "Upload initiated successfully in background.",
"request_id": "1a2b3c4d5e...",
"total_platforms": 2
}
- 202 Accepted (scheduled)
{
"success": true,
"job_id": "scheduler_job_456",
"scheduled_date": "2025-09-22T10:00:00Z"
}
-
400 Bad Request
- Missing
user,platform[], Pinterest withoutpinterest_board_id, Reddit withoutsubreddit, invalid platforms, invalidscheduled_date.
- Missing
-
401 Unauthorized:
{ "success": false, "message": "Invalid or expired token" } -
403 Forbidden (plan restrictions)
-
404 Not Found (e.g., user not found)
-
429 Too Many Requests (monthly limit exceeded; includes current usage)
{
"success": false,
"message": "This upload would exceed your monthly limit.",
"usage": { "count": 10, "limit": 10, "last_reset": "..." }
}
- 500 Internal Server Error:
{ "success": false, "error": "Detailed error message" }
Notes
- When async or when sync falls back to background, use
GET /api/uploadposts/status?request_id={request_id}to poll progress. - Per-platform results may include fields like
url,post_id(s), and platform-specific metadata orerror.