TikTok Photo Post API: Official Endpoint and Examples
TikTok has an official API for photo posts and carousels. Call POST https://open.tiktokapis.com/v2/post/publish/content/init/, set media_type to PHOTO, and provide one to 35 image URLs. Use DIRECT_POST to publish or MEDIA_UPLOAD to send the content into TikTok’s editing flow.
The same endpoint handles a single photo and a carousel: one item in photo_images is a single-photo post; multiple items create a multi-photo post.
TikTok photo API requirements at a glance
| Requirement | Current documented value |
|---|---|
| Endpoint | /v2/post/publish/content/init/ |
| HTTP method | POST |
| Direct-publish scope | video.publish |
| Draft-upload scope | video.upload |
| Media type | PHOTO |
| Transfer method | PULL_FROM_URL |
| Photos per request | 1–35 URLs |
| Rate limit | 6 requests/minute per user access token |
| Title limit | 90 UTF-16 runes |
| Description limit | 4,000 UTF-16 runes |
Before Direct Post, TikTok requires the application to query current creator information and render the supported privacy choices. Do not hard-code PUBLIC_TO_EVERYONE as a default.
Direct Post request for a carousel
In short: Send an authorized access token, choose a privacy value returned by creator info, provide verified HTTPS image URLs, and save the returned publish_id so your system can poll the final status.
curl --fail-with-body \
-X POST https://open.tiktokapis.com/v2/post/publish/content/init/ \
-H "Authorization: Bearer $TIKTOK_ACCESS_TOKEN" \
-H "Content-Type: application/json; charset=UTF-8" \
-d '{
"media_type": "PHOTO",
"post_mode": "DIRECT_POST",
"post_info": {
"title": "Three launch details",
"description": "Swipe through the release notes. #product",
"privacy_level": "PUBLIC_TO_EVERYONE",
"disable_comment": false,
"auto_add_music": true,
"brand_content_toggle": false,
"brand_organic_toggle": true
},
"source_info": {
"source": "PULL_FROM_URL",
"photo_cover_index": 0,
"photo_images": [
"https://media.example.com/launch/01.webp",
"https://media.example.com/launch/02.webp",
"https://media.example.com/launch/03.webp"
]
}
}'
Replace the privacy value with an option returned for the actual creator. The example marks the content as promoting the creator’s own business; commercial-content fields must reflect the real post.
JavaScript example
async function createTikTokPhotoPost(accessToken, imageUrls, privacyLevel) {
if (imageUrls.length < 1 || imageUrls.length > 35) {
throw new Error("TikTok photo posts require 1 to 35 image URLs")
}
const response = await fetch(
"https://open.tiktokapis.com/v2/post/publish/content/init/",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json; charset=UTF-8",
},
body: JSON.stringify({
media_type: "PHOTO",
post_mode: "DIRECT_POST",
post_info: {
title: "Product details",
description: "Swipe for the complete walkthrough.",
privacy_level: privacyLevel,
disable_comment: false,
auto_add_music: true,
brand_content_toggle: false,
brand_organic_toggle: false,
},
source_info: {
source: "PULL_FROM_URL",
photo_cover_index: 0,
photo_images: imageUrls,
},
}),
},
)
const body = await response.json()
if (!response.ok || body.error?.code !== "ok") {
throw new Error(body.error?.message || `TikTok returned ${response.status}`)
}
return body.data.publish_id
}
Treat publish_id as durable job state—not proof that the post is already visible. Poll TikTok’s publish-status endpoint or process its status webhooks until the job is terminal.
Direct Post versus Media Upload
In short: Direct Post publishes from your application after the required user controls and consent. Media Upload sends a draft to TikTok, where the creator opens an inbox notification and completes the editing and publishing flow.
| Mode | Scope | Result | Best for |
|---|---|---|---|
DIRECT_POST |
video.publish |
Publishing starts immediately | Approved scheduling products |
MEDIA_UPLOAD |
video.upload |
Draft continues in TikTok | Workflows that require TikTok editing |
For Media Upload, remove Direct Post-only fields such as privacy and use post_mode: "MEDIA_UPLOAD". TikTok currently requires a sufficiently recent TikTok application version for that photo-upload flow.
Required UX and compliance controls
Building the HTTP call is only part of a compliant integration. TikTok’s Direct Post guidelines require applications to:
- Fetch current creator info when rendering the publishing screen.
- Display the creator’s nickname and the privacy options TikTok returns.
- Require a manual privacy selection; do not preselect one.
- Let the creator control comments. Duet and Stitch do not apply to photo posts.
- Collect the correct commercial-content disclosure.
- Show a preview and obtain express consent before sending the content.
- Keep captions and hashtags editable.
- Avoid promotional watermarks or logos added by the integration.
- Show publishing status while TikTok processes the post.
Unaudited clients are limited to private viewing. TikTok also documents a five-user daily cap for unaudited clients, plus creator and application posting caps that apply more broadly.
Image hosting rules
In short: TikTok photo posts only support PULL_FROM_URL. Serve every image over HTTPS from a URL owned by your developer application, avoid redirects, and keep the resource accessible while TikTok downloads it.
The most common integration mistake is using a signed URL on an unverified host. A URL can be publicly readable and still fail because TikTok has not verified its domain or prefix for your application.
Before launch:
- verify the base domain or exact URL prefix in TikTok for Developers;
- use stable HTTPS URLs without redirects;
- preserve the image order because it controls carousel order;
- select a zero-based
photo_cover_indexthat exists in the array; - test the real production hostname, not only TikTok’s sample media.
Schedule photo posts with Postqued
In short: Postqued supplies the scheduling layer that TikTok’s public endpoint does not. Upload one or more image assets, read the connected creator’s constraints, validate the target, and set dispatchAt for the future publish time.
Postqued uses a static API key for its own API, while the connected TikTok account is authorized through the product’s user flow.
1. Upload the images
For each image, call POST /v2/content/upload, send the bytes to the returned presigned URL, then call POST /v2/content/upload/complete. Save every contentId in carousel order.
2. Read creator info
GET /v2/integrations/ACCOUNT_UUID/creator-info?workspaceId=WORKSPACE_UUID
Use the returned privacy choices rather than assuming public publishing is available.
3. Validate and schedule
{
"workspaceId": "WORKSPACE_UUID",
"contentIds": ["IMAGE_UUID_1", "IMAGE_UUID_2", "IMAGE_UUID_3"],
"targets": [
{
"platform": "tiktok",
"accountId": "ACCOUNT_UUID",
"intent": "publish",
"caption": "Swipe through the launch details.",
"dispatchAt": "2026-08-15T17:00:00Z",
"options": {
"privacyLevel": "PUBLIC_TO_EVERYONE",
"disableComment": false,
"autoAddMusic": true,
"photoCoverIndex": 0,
"commercialContent": false,
"brandContentToggle": false,
"brandOrganicToggle": false,
"authenticContentConfirmed": true
}
}
],
"dryRun": true
}
Send this body to POST https://api.postqued.com/v2/publish. After validation, repeat with dryRun: false and a fresh UUID in the Idempotency-Key header. The live OpenAPI document remains the source of truth for the exact schema.
Common TikTok photo API errors
url_ownership_unverified
The image host or prefix is not verified for the TikTok developer application. Verify it or serve the assets from a verified property.
privacy_level_option_mismatch
The privacy value is absent or not one of the choices returned by creator info. Refresh creator info and require a valid user selection.
scope_not_authorized
The access token does not include video.publish or video.upload for the selected flow. Re-authorize with the required approved scope.
spam_risk_too_many_posts
The creator has reached a posting cap. Stop retrying immediately and surface the provider error to the user.
rate_limit_exceeded
The user access token exceeded the documented request rate. Queue requests and back off rather than switching tokens or hiding the error.
Final checklist
- Use the official
/v2/post/publish/content/init/endpoint. - Fetch creator info before every publishing flow.
- Provide one to 35 verified HTTPS image URLs.
- Use
video.publishfor Direct Post orvideo.uploadfor Media Upload. - Keep privacy and commercial disclosures under user control.
- Save
publish_idand monitor final status. - Complete TikTok’s audit before expecting public Direct Post behavior.
For a managed scheduling layer, see the Postqued TikTok scheduler. For the broader integration decision, read does TikTok have an official scheduling API?.