Skip to main content

1. Overview

TikTok accepts a post as a job and finishes it later, so a TikTok target stays publishing until TikTok reports the post complete or failed. A video publishes publicly. A photo carousel needs a privacy_level. A creator connection follows other privacy and draft rules, listed on that section.

2. Supported media

Single images are not supported, and a post cannot mix a video with images. When you omit media_type, 2 or more images with no video publish as a photo carousel, and anything else publishes as a video. File limits for media you send to SocialAPI (source_type: "media_id" or "url"): videos must be MP4, MOV, or WebM, at most 1 GB, and at least 3 seconds long. Images must be JPEG or WebP and at most 20 MB each. A file outside these limits fails validation with 400 publishing.validation_failed. The longest video depends on the account: read max_video_duration_sec from Creator info. SocialAPI checks that limit when it knows the video’s duration, and a longer video fails validation the same way. TikTok’s own media rules. SocialAPI does not check these before it sends the post. A file outside them fails the target with 422 platform.tiktok.publish_failed, and message holds TikTok’s reason, such as frame_rate_check_failed or picture_size_check_failed. Text limits: a video caption holds 2,200 UTF-16 characters, with at most 30 mentions. For a photo carousel, the post text is the title and holds 90 UTF-16 characters.
Attach media through the media array. Each item sets a source_type: media_id for a file you uploaded to SocialAPI, or url for a public http(s) URL. TikTok pulls the file while the post publishes, so keep the file reachable until the target is published. A platform_attachment_id source returns 422 publishing.media.unsupported_source on TikTok. To upload first, see Media.

3. Create post

Use POST /v1/posts with targets pointing at a TikTok account and publish_now: true. The text field becomes the caption.
Response (HTTP 201):
The target settles later: see Slow publishes and the publishing status.

Draft in the TikTok app

Set post_mode to "inbox" to send a video or a photo carousel to the creator’s TikTok drafts. TikTok then asks the creator for the audience, interaction settings, and disclosures in the app, so SocialAPI ignores privacy_level, the disable_* fields, auto_add_music, the branding fields, is_aigc, and video_cover_timestamp_ms on a draft. A video draft carries no caption: the creator writes it in the app. A photo draft keeps the post text as its title. A draft needs the video.upload scope, and it returns no public post ID and no permalink.

Platform data fields

Send these keys in platform_data.tiktok on the post, which applies them to every TikTok target. To set them for one target, send them flat in that target’s platform_data (targets[].platform_data, with no tiktok key). When both set the same key, the target’s value wins. SocialAPI forwards any additional keys in platform_data.tiktok that the table above lists, and no others. TikTok has no other publish options that SocialAPI passes through: an unlisted key is ignored without a warning.

Creator info and validation

The longest video and the interaction locks differ per account. Call GET /v1/accounts/{id}/creator-info first (Creator info), then dry-run the post with POST /v1/posts/validate:
Response (HTTP 200):
When TikTok cannot be reached for the check, warnings holds one entry on the field creator_info, and the photo privacy check and the video duration check are skipped. The media rules and the post_mode and privacy_level checks still run.

Scheduling

Set scheduled_at to an ISO 8601 timestamp (UTC) instead of publish_now. SocialAPI holds the post and publishes it at that time. A photo carousel still needs privacy_level. On a creator connection, a video needs it too.

4. Update post

TikTok gives apps no edit call. PATCH /v1/posts/{pid} edits only a post in draft, scheduled, or failed status, so a published TikTok post returns 409 post.state_invalid. Delete the post in the TikTok app and publish a new one.

5. Delete post

TikTok gives apps no deletion call. DELETE /v1/posts/{pid} returns HTTP 200 with results[].outcome: "not_supported" for the TikTok target, and the post stays on TikTok. POST /v1/posts/{pid}/unpublish returns 501 resource.not_supported for a TikTok target. Delete the post in the TikTok app. For a cross-platform post, the other platforms are still deleted or unpublished. See Delete a post.

6. Retrieve posts

GET /v1/posts?platform=tiktok&account_ids={id} returns the posts SocialAPI has stored for the account, including posts published outside SocialAPI. A post published through SocialAPI appears when its target is published. POST /v1/platforms/tiktok/accounts/{id}/sync reads the 20 most recent posts from TikTok immediately: see Sync videos. Response (HTTP 200) for one stored video:
GET /v1/posts/{pid}/metrics reads the current counts from TikTok. It reads the account’s 20 most recent posts and reuses that read for 10 minutes. For a post outside those 20, the target returns 404 resource.not_found. A draft has no platform_post_id, so its target is not in the response.
The view count has a different key on each endpoint: metrics.extra.view_count on GET /v1/posts, and metrics.views with metrics.extra.views on GET /v1/posts/{pid}/metrics. Each is absent while the count is 0. TikTok updates the counts with a delay of 24 to 48 hours. Reach, saves, and watch time are not available.

7. Quirks, errors, and recovery

Privacy level differs for videos and photos

This section covers the default connection. A creator connection requires privacy_level on every published post, from the account’s privacy_level_options. A draft needs none. Every video publishes publicly, and TikTok takes no privacy setting for it. Omit privacy_level on a video, or send PUBLIC_TO_EVERYONE. Any other value, or a value that is not a string, fails with 400 validation.privacy_level_unsupported, and nothing is sent to TikTok. meta.privacy_level carries the value you sent. A photo carousel needs privacy_level. A photo without it fails with 400 validation.privacy_level_required. PUBLIC_TO_EVERYONE is always the safe choice. TikTok can allow other levels for the account (MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY), and a photo carousel accepts those. Creator info lists only PUBLIC_TO_EVERYONE, so it does not show them. A level the account does not allow fails with 400 validation.invalid_privacy_level, which carries the value you sent in meta.privacy_level. A draft needs no privacy_level.

Photo carousels need 2 to 35 images

A photo post with fewer than 2 or more than 35 images fails with 400 validation.media_count. TikTok has no single-image post.

Media type must match the file

TikTok will not build a video out of an image. A single image with no media_type resolves to a video, and a post like that fails with 400 validation.media_type_mismatch before anything is sent. Set media_type to "photo" and attach 2 or more JPEG or WebP images. A media_type that is neither video nor photo fails with 400 validation.unsupported_media_type. A video post with no media fails with 400 validation.media_required.

Photo posts accept only JPEG and WebP

A photo carousel that holds a PNG, AVIF, GIF, or a video fails with 400 validation.unsupported_photo_format, which names the offending format. Convert the images to JPEG or WebP before uploading.

Photo titles hold 90 characters

A photo carousel whose text is longer than 90 UTF-16 characters fails validation on the field title.

disable_duet and disable_stitch are ignored on photo posts

disable_duet and disable_stitch set to true on a photo carousel have no effect. Validation returns a warning on the field interactions, not an error.

Branded content cannot be private

On a photo carousel, brand_content_toggle: true with privacy_level: "SELF_ONLY" fails with 400 validation.branded_content_private.

Posting caps

SocialAPI caps each account at 13 posts per 24 hours and 25 per hour: a post beyond either cap returns 429 publishing.velocity_limit. See Posting velocity caps. TikTok also limits each account to 6 posts per minute and 15 per day, for the video call and for the photo call. SocialAPI does not enforce the 6 per minute: TikTok refuses a 7th post within a minute. A post TikTok refuses fails the target: read targets[].error.code and targets[].error.message.

Slow publishes and the publishing status

TikTok often settles after the request that created the post returned, either because it is still processing the file or because it has not yet exposed the post ID. In both cases the target stays status: "publishing" with platform_post_id and permalink absent. SocialAPI then settles it on its own: published with its ID and permalink, or failed if TikTok rejected it. publishing is not terminal, so treat it as “still working”:
  • Do not confirm success on it. Only published is a completed publish.
  • Do not retry or republish it. The post can already be live on TikTok, so a retry risks a duplicate post.
  • Keep reading GET /v1/posts/{pid}, or wait for the webhook. The post.published, post.partial, and post.failed events fire when the post reaches its final status, including after the original request returned.
If TikTok reports the post live but has not returned its ID 2 hours after publishing started, the target settles at published without platform_post_id or permalink. A target TikTok still reports as processing 2 hours after publishing started fails with 500 system.internal. Check the TikTok profile before retrying such a target: the post can still have gone live. A draft settles at published without platform_post_id or permalink once TikTok has placed it in the creator’s TikTok inbox.

Errors on a failed target

A publish that fails puts a structured error on the target, in targets[].error, with its code. Every code is in Errors.
  • 401 platform.tiktok.auth: TikTok’s authorization for the account ended. Reconnect the account. Later calls return 403 account.reconnection_required.
  • 401 platform.tiktok.unauthorized: TikTok refused the call as unauthorized without saying the authorization ended. The account stays usable. Retry, and reconnect if it repeats.
  • 403 platform.tiktok.40001, 403 platform.tiktok.40118, 403 platform.tiktok.40125: the authorization lacks a scope, such as video.publish. Reconnect the account.
  • 429 platform.tiktok.rate_limit: TikTok’s own request limit. Wait 1 minute, then retry.
  • 400 platform.tiktok.40002: TikTok refused a parameter or a media file. The same status comes with the codes 40000, 40011, 40904 to 40908, 40914, and 40915. message carries TikTok’s reason. Fix the field it names.
  • 422 platform.tiktok.publish_failed: TikTok rejected the post while processing it, or could not report the outcome. message carries TikTok’s reason.
  • 502 platform.tiktok.api_error: TikTok returned no usable answer, or accepted the post without a publish ID. Check the account in the TikTok app before retrying.
  • Any other TikTok code returns 502, with that code after platform.tiktok. and TikTok’s reason in message.

Recovery

  • Validation error. Fix the field the issue names, then send the post again.
  • Auth error. Reconnect the TikTok account through the OAuth flow.
  • Failed target. Read targets[].error, then send POST /v1/posts/{pid}/retry. See Delivery.

8. Full worked example

This example reads creator info, validates the post, creates it, and reads the result. Step 1: Read creator info
Check can_post and max_video_duration_sec. A locked interaction in interaction_settings forces that setting off. Step 2: Upload media Upload the video and verify it as described in Media. The result is a media_id, here f47ac10b-58cc-4372-a567-0e02b2c3d479. Step 3: Validate
Response (HTTP 200): {"valid": true, "errors": [], "warnings": []} Step 4: Create the post
Response (HTTP 201): the post with status: "publishing", as in Create post. Step 5: Check the status
Response (HTTP 200) once TikTok finished:
If TikTok rejects the file while processing, the target is failed with error. Read it, fix the cause, then send POST /v1/posts/7c9e6679-7425-40de-944b-e07fc1f90ae7/retry.

9. Required OAuth scopes

SocialAPI’s TikTok app requests these scopes during the OAuth flow. You configure nothing. The full list is in TikTok scopes. Publishing uses video.publish, user.info.username, and, for post_mode: "inbox", video.upload. Retrieving posts uses video.list. The scopes a scoped API key needs, the credit cost of a post, and the MCP tools that publish are on Publishing.
Last modified on October 16, 2026