Skip to main content
Socialift
Guide

TikTok Content Posting API: publishing videos and photos

The TikTok Content Posting API has two modes. Direct Post (scope video.publish) publishes straight to the creator's profile; Upload (video.upload) sends the video to the creator's TikTok inbox to finish in the app. Before every Direct Post you query creator_info. Until TikTok audits your app, every post is private (SELF_ONLY).

Updated:

Direct Post or Upload: which one do you need?

Use Direct Post when the user finishes the post inside your app: your app collects the caption, privacy and interaction settings, and TikTok publishes right after processing. Use Upload when the creator should edit inside TikTok: your app transfers the media, the creator gets an inbox notification and completes the post in the TikTok app.

Both modes share the same mechanics: an init request returns a publish_id (plus an upload_url for file uploads), the media is transferred, and you track the outcome with the status endpoint or Content Posting webhooks.

Direct Post comes with stricter rules — a mandatory creator info query, a prescribed posting UI and an audit for public visibility — because the content goes live without the creator opening TikTok.

Direct Post vs Upload compared

Direct Post vs Upload compared — Capability matrix by platform
AspectDirect PostUpload (inbox)
Scopevideo.publishvideo.upload
Video endpoint/v2/post/publish/video/init//v2/post/publish/inbox/video/init/
Photo endpoint/v2/post/publish/content/init/, post_mode = DIRECT_POST/v2/post/publish/content/init/, post_mode = MEDIA_UPLOAD
Who sets caption and privacyYour app, from the user's explicit choicesThe creator, inside TikTok
Creator info queryRequired before each postNot part of the documented flow
Volume limitPer-creator cap per 24 hours, typically around 15 postsAt most 5 pending shares within any 24 hours
Final statusPUBLISH_COMPLETESEND_TO_USER_INBOX, then the creator posts
Socialift SDKpublish_video, publish_photosupload_video, publish_photos(draft=True)

How to publish a video with Direct Post

Order matters: TikTok's guidelines require the creator info query and a specific posting UI before the init call.

  1. Get video.publish authorization

    The creator must have authorized your app for video.publish through Login Kit. Keep the access token fresh — it lives 24 hours.

  2. Query creator info

    POST /v2/post/publish/creator_info/query/ returns the creator's nickname and avatar, privacy_level_options, comment_disabled, duet_disabled, stitch_disabled and max_video_post_duration_sec. Errors such as spam_risk_too_many_posts or reached_active_user_cap mean you should not offer posting right now.

  3. Show a compliant posting screen

    Display the creator's nickname, a privacy dropdown with no default value, interaction toggles that are off by default (greyed out if the creator disabled them), a commercial content disclosure switch, a preview and the Music Usage Confirmation consent. Tell users processing can take a few minutes.

  4. Initialize the post

    Send post_info (title, privacy_level, disable_comment, disable_duet, disable_stitch, branded content toggles) and source_info with FILE_UPLOAD or PULL_FROM_URL. The response contains publish_id and, for file uploads, upload_url.

  5. Transfer the media

    For FILE_UPLOAD, PUT the chunks to upload_url within one hour. For PULL_FROM_URL, TikTok downloads the file from your verified URL itself.

  6. Track the result

    Poll /v2/post/publish/status/fetch/ with the publish_id or subscribe to Content Posting webhooks, and show the final outcome to the user.

privacy_level values

Send only a value that creator info returned for this creator — anything else is rejected with privacy_level_option_mismatch.

privacy_level values — Capability matrix by platform
ValueWho can see the post
PUBLIC_TO_EVERYONEEveryone
MUTUAL_FOLLOW_FRIENDSFriends — accounts that follow each other
FOLLOWER_OF_CREATORThe creator's followers
SELF_ONLYOnly the creator; the only value an unaudited client can use

The list depends on the creator's account settings, so never hard-code it.

Direct Post in Python

The SDK sends the init request, uploads file chunks and, with wait=True, polls the status until the post is published or fails.

tiktok_direct_post.py
from socialift import TikTok

async def post_video(token: str, privacy: str, caption: str) -> dict:
    async with TikTok.from_env() as tt:
        info = await tt.creator_info(token)
        if privacy not in info["privacy_level_options"]:
            raise ValueError(f"{privacy} is not allowed for this creator")

        return await tt.publish_video(
            token,
            video="renders/launch.mp4",      # FILE_UPLOAD, chunked by the SDK
            title=caption,
            privacy_level=privacy,           # SELF_ONLY until the app is audited
            disable_comment=info.get("comment_disabled", False),
            disable_duet=info.get("duet_disabled", False),
            disable_stitch=info.get("stitch_disabled", False),
            wait=True,
        )

publish_video defaults to SELF_ONLY, the only level an unaudited client may use. wait=True polls the status every 3 seconds for up to 2 minutes and raises ApiError carrying TikTok's fail_reason if the post fails.

Passing video_url= instead of video= switches to PULL_FROM_URL. If the domain is not verified, the SDK raises PermissionError for url_ownership_unverified.

What unaudited apps can and cannot do

TikTok restricts every Content Posting API client that has not passed its audit. All content it posts is limited to private viewing (SELF_ONLY), creator accounts must be set to private at the time of posting, and no more than 5 users can post through it in a 24-hour window. Trying to post publicly returns unaudited_client_can_only_post_to_private_accounts.

That is enough to build and demo an integration, but not to launch it. After testing you apply for the audit, which checks compliance with TikTok's terms and the content sharing guidelines. The sandbox does not help here: it does not offer Content Posting API access for public videos.

Posts created before the audit stay private. To make one public, the account owner first switches the account to public and then changes that post's privacy to Everyone in TikTok.

PULL_FROM_URL vs FILE_UPLOAD

Both sources work for Direct Post and Upload videos. Photo posts only support PULL_FROM_URL.

PULL_FROM_URL vs FILE_UPLOAD — Capability matrix by platform
AspectPULL_FROM_URLFILE_UPLOAD
How it worksTikTok downloads the media from your URLYou PUT the bytes to the returned upload_url
PrerequisiteDomain or URL prefix verified in URL propertiesNone
Address rulesHTTPS, no redirects, a domain rather than an IP; the download times out one hour after it starts, so keep the URL reachableupload_url is valid for one hour
ChunkingNot applicableChunks of 5–64 MB, last chunk up to 128 MB; files under 5 MB go in one piece; up to 1000 chunks, in order
Chunk countNot applicabletotal_chunk_count = video_size ÷ chunk_size, rounded down
HeaderNot applicableEach chunk carries Content-Range: bytes first-last/total
Typical errorurl_ownership_unverifiedHTTP 403 when upload_url has expired
Socialift SDKvideo_url=, photo_urls=video= (bytes or file path), optional chunk_size=
Notes and limits

URL prefix verification is literal: verifying https://example.com/videos/user/ covers https://example.com/videos/user/123/a.mp4 but not https://example.com/videos/2023/user/123/a.mp4.

Media requirements

Media requirements — Capability matrix by platform
MediaRequirement
Video containerMP4 (recommended), WebM, MOV
Video codecH.264 (recommended), H.265, VP8, VP9
Frame rate23–60 FPS
Resolution360–4096 px on each side
File sizeUp to 4 GB
DurationUp to max_video_post_duration_sec from creator info
Video titleUp to 2200 UTF-16 runes
PhotosWebP or JPEG, up to 1080p, up to 20 MB each, up to 35 images per post
Photo post title / descriptionUp to 90 / 4000 UTF-16 runes

Photo posts, drafts and status checks

Photos always come from verified URLs. Inbox uploads end in SEND_TO_USER_INBOX, so check them with publish_status instead of waiting for publication.

tiktok_photos_and_drafts.py
from socialift import TikTok

async def carousel_and_draft(token: str) -> None:
    async with TikTok.from_env() as tt:
        # creator_info() before Direct Post, as in the video example
        carousel = await tt.publish_photos(
            token,
            photo_urls=[
                "https://media.example.com/tiktok/look-1.jpg",
                "https://media.example.com/tiktok/look-2.jpg",
            ],
            title="Autumn lookbook",
            description="Two looks from the new collection",
            privacy_level="SELF_ONLY",
            cover_index=0,
            wait=True,
        )
        print(carousel["status"]["status"])   # PUBLISH_COMPLETE

        draft = await tt.upload_video(token, video="renders/raw-cut.mp4")
        state = await tt.publish_status(draft["publish_id"], token)
        print(state["status"])                # PROCESSING_UPLOAD or SEND_TO_USER_INBOX

publish_photos(..., draft=True) sends photos to the creator's inbox in MEDIA_UPLOAD mode; that requires the video.upload scope.

Post status values

Post status values — Capability matrix by platform
StatusMeaning
PROCESSING_UPLOADFile chunks are being uploaded (FILE_UPLOAD only)
PROCESSING_DOWNLOADTikTok is downloading from your URL (PULL_FROM_URL only)
SEND_TO_USER_INBOXUpload mode: the notification reached the creator's inbox
PUBLISH_COMPLETEThe content was posted
FAILEDProcessing stopped; see fail_reason, e.g. file_format_check_failed, duration_check_failed, frame_rate_check_failed, video_pull_failed, spam_risk_too_many_posts

publicaly_available_post_id (spelled that way in the API) is returned only once the post is public and approved; private posts have no public ID.

Production checklist for TikTok posting

  • Query creator info before every Direct Post and build the privacy dropdown from privacy_level_options.
  • Leave privacy and interaction settings without defaults; grey out whatever the creator disabled.
  • Stay under 6 init requests and 30 status requests per minute per user token.
  • Treat spam_risk_too_many_posts and spam_risk_too_many_pending_share as a pause, not a retry loop.
  • Never superimpose logos, watermarks, links or promotional text on content shared to TikTok.
  • Keep media URLs on a verified HTTPS prefix without redirects.
  • Log the log_id from every error response for TikTok support.

← Back to blog

Frequently asked questions

Can I publish public TikTok videos via the API without an audit?

No. An unaudited client can only post with SELF_ONLY visibility, the creator's account must be private at posting time, and up to 5 users can use it in 24 hours. Public posting requires your app to pass TikTok's audit.

Why does TikTok return url_ownership_unverified?

In PULL_FROM_URL mode the media URL must belong to a domain or URL prefix verified under URL properties in the TikTok developer portal. Verify the domain, or upload the file with FILE_UPLOAD, which needs no verification.

How many posts per day can the Content Posting API publish?

Direct Post has a per-creator cap per 24 hours — typically around 15 posts, varying by creator. Hitting it returns spam_risk_too_many_posts. In Upload mode there can be at most 5 pending shares within any 24 hours.

Do I have to call creator_info before every post?

Yes. TikTok's rules require fetching the creator's latest information before a Direct Post: allowed privacy levels, disabled interactions and the maximum video duration can change at any time.

Can I upload photos as files?

No. Photo posts only accept PULL_FROM_URL, so images are fetched from HTTPS links on a verified domain. A single post can contain up to 35 images.

Can my app add a logo or watermark to the video?

No. TikTok's guidelines forbid apps and integrations from superimposing a brand name, logo, watermark, link or promotional text on content shared to TikTok.

Sources

  1. TikTok for Developers — Get started: Direct Post
  2. TikTok for Developers — Direct Post reference
  3. TikTok for Developers — Media transfer guide
  4. TikTok for Developers — Content sharing guidelines
  5. TikTok for Developers — Photo post reference
  6. TikTok for Developers — Get post status

Related pages