Skip to main content

Upload Photos

Upload photos to various social media platforms using this endpoint.

Note: This feature is a work in progress. More parameters and social media platforms will be added in future updates.

Endpoint

POST /api/upload_photos

Headers

NameValueDescription
AuthorizationApikey your-api-key-hereYour API key for authentication

Common Parameters

NameTypeRequiredDescription
userStringYesUser identifier
platform[]ArrayYesPlatform(s) to upload to. Supported values: tiktok, instagram, linkedin, facebook, x, threads, pinterest
photos[]ArrayYesArray of photo files to upload (can be file uploads or photo URLs)
titleStringYesDefault title of the post
descriptionStringNoOptional extended text used on TikTok photo descriptions, LinkedIn commentary, Facebook descriptions, Pinterest notes, and Reddit bodies. Ignored elsewhere.
scheduled_dateString (ISO-8601)NoOptional 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_uploadBooleanNoIf true, the request returns immediately with a request_id and processes in the background. See Upload Status.

Important: If you set async_upload to false but the upload takes longer than 59 seconds, it will automatically switch to asynchronous processing to avoid timeouts. In that case, use the request_id with the Upload Status endpoint to check the upload status and result.

This endpoint supports simultaneous photo uploads to multiple social media platforms.

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

NameTypeRequiredDescriptionDefault
linkedin_titleStringNoSpecific title for the LinkedIn post. Fallbacks to title.title
linkedin_description or descriptionStringNoSent as the post commentary. If omitted, we reuse title.title
visibilityStringNoVisibility setting for the post (accepted value: "PUBLIC")PUBLIC
target_linkedin_page_idStringNoLinkedIn page ID to upload photos to an organization"107579166"

Facebook

NameTypeRequiredDescriptionDefault
facebook_titleStringNoSpecific title for the Facebook post. Fallbacks to title.title
facebook_page_idStringYesFacebook Page ID where the photos will be posted-
facebook_media_typeStringNoType 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_id is 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 an available_pages list 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)

NameTypeRequiredDescriptionDefault
x_titleStringNoSpecific title for the tweet. Fallbacks to title.title
x_long_text_as_postBooleanNoWhen true, publishes long text as a single post. Otherwise, creates a thread.false

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

NameTypeRequiredDescriptionDefault
tiktok_titleStringNoSpecific title for the TikTok post. Fallbacks to title.title
post_modeStringNoControls 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_levelStringNoAccepted values: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY.PUBLIC_TO_EVERYONE
auto_add_musicBooleanNoAutomatically add background music to photosfalse
disable_commentBooleanNoDisable comments on the postfalse
brand_content_toggleBooleanNoSet to true for paid partnerships that promote third-party brands.false
brand_organic_toggleBooleanNoSet to true when promoting the creator's own business.false
photo_cover_indexIntegerNoIndex (starting at 0) of the photo to use as the cover/thumbnail for the TikTok photo post0
tiktok_description or descriptionStringNoFor photo posts, used as description inside post_info.title

Instagram

NameTypeRequiredDescriptionDefault
instagram_titleStringNoSpecific title for the Instagram post. Fallbacks to title.title
media_typeStringNoType of media ("IMAGE" or "STORIES")"IMAGE"

The global description field is ignored for Instagram photo uploads.

Threads

NameTypeRequiredDescriptionDefault
threads_titleStringNoSpecific title for the Threads post. Fallbacks to title.title

The global description field is ignored for Threads photo uploads.

Pinterest

NameTypeRequiredDescriptionDefault
pinterest_titleStringNoSpecific title for the Pinterest Pin. Fallbacks to title.title
pinterest_description or descriptionStringNoPopulates the Pin description. If omitted, we reuse title.title
pinterest_board_idStringYesPinterest board ID to publish the photo to.-
pinterest_alt_textStringNoAlt text for the image.-
pinterest_linkStringNoDestination link for the photo Pin.-

Example Requests

Upload Photos to Instagram

curl \
-H 'Authorization: Apikey your-api-key-here' \
-F 'photos[]=@/path/to/your/image1.jpg' \
-F 'user="test"' \
-F 'platform[]=instagram' \
-F 'title="My Photo Title"' \
-X POST https://api.upload-post.com/api/upload_photos

Upload Photos to Facebook Using URLs

curl \
-H 'Authorization: Apikey your-api-key-here' \
-F 'photos[]="https://example.com/images/photo1.jpg"' \
-F 'photos[]="https://example.com/images/photo2.jpg"' \
-F 'user="test"' \
-F 'platform[]=facebook' \
-F 'facebook_page_id="123456789"' \
-F 'title="My Photo Title"' \
-F 'description="Check out these photos!"' \
-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": "Photo 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 without pinterest_board_id, Reddit without subreddit, invalid platforms, invalid scheduled_date.
  • 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 or error.

Platform-specific example: TikTok

{
"results": {
"tiktok": {
"publish_id": "string",
"status": "PUBLISH_COMPLETE",
"success": true,
"url": "https://www.tiktok.com/@username/photo/publish_id"
}
},
"success": true,
"usage": {
"count": 25,
"last_reset": "2025-05-31T19:09:09.984073",
"limit": 120
}
}
FieldTypeDescription
results.tiktok.publish_idStringUnique identifier for the published post
results.tiktok.statusStringPublishing status (e.g., "PUBLISH_COMPLETE")
results.tiktok.successBooleanIndicates if the upload was successful
results.tiktok.urlStringDirect URL to the published TikTok post
successBooleanOverall API request success status
usage.countNumberCurrent API usage count
usage.last_resetStringTimestamp of last usage counter reset
usage.limitNumberAPI usage limit