# TikTok's Content Posting API, explained

TikTok's Content Posting API has two routes to a finished post. **Upload** sends a draft to the creator's TikTok
inbox; they finish and publish it in the app. **Direct Post** publishes from your integration without that in-app
step. An upload is not a published post, and permission to test Direct Post is not permission to publish publicly.

TikTok's developer documentation was checked on October 26, 2026. The linked pages are the source for TikTok's rules
below; the final section separately describes Flaghand's merged implementation on that date.

## Inbox upload or Direct Post?

Both need a registered TikTok developer app, approval for the relevant scope, and the creator's authorization of
that scope. The scope names say `video`, but they cover photos too.

| | Inbox upload | Direct Post |
|---|---|---|
| User-granted scope | `video.upload` | `video.publish` |
| Video initialization | `POST /v2/post/publish/inbox/video/init/` | `POST /v2/post/publish/video/init/` |
| Photo initialization | `POST /v2/post/publish/content/init/` with `post_mode: "MEDIA_UPLOAD"` and `media_type: "PHOTO"` | The same endpoint with `post_mode: "DIRECT_POST"` and `media_type: "PHOTO"` |
| Creator's final step | Open the inbox notification, edit and publish in TikTok | Choose posting settings and consent in the integration before it sends the post |
| Result to distinguish | `SEND_TO_USER_INBOX`: delivered for the creator to finish | `PUBLISH_COMPLETE`: publication finished, not necessarily public visibility |

TikTok's [upload guide](https://developers.tiktok.com/doc/content-posting-api-get-started-upload-content) and
[Direct Post guide](https://developers.tiktok.com/doc/content-posting-api-get-started) document these as different
flows, not two names for automatic publishing.

For video, `FILE_UPLOAD` means sending bytes with `PUT` to the returned upload URL. `PULL_FROM_URL` means TikTok
fetches a hosted video. Photos use `PULL_FROM_URL` only. The
[sharing guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines) require URL pull for media already
on your server; file upload is for video on the user's device. Hosted media needs an ownership-verified domain or URL
prefix. An initialization response's `publish_id` identifies the attempt; it isn't proof that the post is live.

Follow it with `POST /v2/post/publish/status/fetch/`. TikTok's
[status reference](https://developers.tiktok.com/doc/content-posting-api-reference-get-video-status) distinguishes
processing, inbox delivery, publication and failure. For an inbox upload, `PUBLISH_COMPLETE` means the creator went on
to publish in TikTok. The status field `publicaly_available_post_id` supplies IDs only after public publication and
moderation, not for private posts.

## What an unaudited app can do

TikTok's [Direct Post guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines) impose three
restrictions before the client passes its audit:

- **At most 5 posting users within a 24-hour window.** That's users, not 5 posts per user.
- **Each posting account must be private at posting time.** Choosing Only me on a public account isn't enough.
- **Every Direct Post must use `SELF_ONLY`**, TikTok's Only me visibility.

These are Direct Post restrictions. They don't turn the separate inbox-upload flow into a private published post:
that flow hands a draft to its creator, who makes the final choices in TikTok. Inbox upload still needs its own app
and user authorization and is subject to the upload limits below.

Removing Direct Post's private-only restriction requires a TikTok audit. Passing an audit doesn't remove the
creator's privacy settings or TikTok's posting limits. Nor does it automatically make old Only me posts public:
TikTok says the creator must make the account public, then change each post's visibility to Everyone.

## What the audit asks of your integration

The [Content Sharing Guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines) are the Direct Post
integration checklist, not just a media-format reference:

- **A product for a broad audience of creators.** A private utility for accounts you or your team manage isn't an
  acceptable use case. Neither is copying arbitrary content from other platforms to TikTok. Creators should publish
  their own original work.
- **An account-aware posting screen.** Show the destination nickname, a media preview and editable text. Fetch current
  creator info, let the creator choose visibility with no default, and respect their available interaction settings.
- **Creator control and consent.** Comments, Duet and Stitch start off; unavailable controls are disabled. Photos have
  comments, not Duet or Stitch. Explain processing time and obtain express consent before sending media to TikTok.
- **Commercial disclosure.** The disclosure toggle starts off. If enabled, the creator chooses their own brand,
  third-party branded content, or both. Show the appropriate Promotional content or Paid partnership notice; branded
  content cannot use private visibility. Include TikTok's Music Usage Confirmation and, where required, Branded
  Content Policy declaration before the publishing control.
- **No promotional additions to the media.** Don't insert your app's watermark, logo or promotional text into the
  creator's post. Report the eventual result, not just a successful upload request.

TikTok's separate [app review guidelines](https://developers.tiktok.com/doc/app-review-guidelines) also ask for a
finished product, a publicly accessible website with working Privacy Policy and Terms links, correct web redirect
configuration, and an explanation of every requested product and scope. The submission includes 1 to 5 end-to-end
demo videos, each no larger than 50 MB, showing the actual integration and its user actions. For an app not previously
approved, the recording must demonstrate the integration using the Developer Portal sandbox. General app review and
the Direct Post audit aren't interchangeable; requesting a scope or submitting a recording isn't audit approval.

## Photo posts: what the API accepts

A photo slideshow is a `PHOTO` request, not a video assembled from images. TikTok's
[photo reference](https://developers.tiktok.com/doc/content-posting-api-reference-photo-post) supports both
`MEDIA_UPLOAD` and `DIRECT_POST`. Inbox photo upload requires TikTok app version 31.8 or later.

| Photo-post field | TikTok's documented constraint |
|---|---|
| `photo_images` | Up to 35 image URLs, in order |
| Image bytes | WebP or JPEG, up to 20 MB per image |
| Resolution | The media guide says "Maximum 1080p"; it doesn't specify a universal width-by-height pair |
| `title` | Up to 90 |
| `description` | Up to 4,000 |
| `photo_cover_index` | Required, zero-based: 0 selects the first image |
| Transfer | `PULL_FROM_URL` only, from an ownership-verified domain or URL prefix |

TikTok describes the title and description lengths as "UTF-16 runes"; don't assume a visible emoji always counts as
one. The [media transfer guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide) supplies
the image format, size and resolution rules. It requires HTTPS without redirects and a URL that stays accessible
while TikTok downloads. A PNG accepted by your own app must be converted to a supported format before TikTok pulls it.
The API doesn't make every format accepted by TikTok's phone picker an accepted API format.

## creator_info: ask the account, don't guess

Before rendering the Direct Post screen, call
[`POST /v2/post/publish/creator_info/query/`](https://developers.tiktok.com/doc/content-posting-api-reference-query-creator-info)
with the user's `video.publish` token. Use a fresh response each time the screen opens, not a shared set of settings
for every account.

It returns the creator's username, nickname and avatar, `privacy_level_options`, `comment_disabled`, `duet_disabled`,
`stitch_disabled`, and `max_video_post_duration_sec`. Populate visibility from that returned list, with nothing
preselected. Disable interactions TikTok disallows, and reject a video longer than the returned duration. Photo-only
integrations can ignore Duet, Stitch and the video-duration field. The example's 300 seconds isn't a universal limit.

Check `error.code`, even for HTTP 200: only `ok` is success. Creator-info errors can mean the creator cannot post,
has reached their daily allowance, or the client has reached its active-creator cap. There is no numeric
remaining-posts counter or quota-reset timestamp in this response.

## Posting limits are not request-rate limits

These are TikTok's documented limits, not extra limits added by Flaghand:

| Limit | What TikTok documents |
|---|---|
| Unaudited Direct Post users | Up to 5 users within 24 hours |
| Active Direct Post creators per client | A 24-hour cap based on the estimate submitted for audit; no single universal number |
| Direct Posts per creator | Typically around 15 posts within 24 hours, variable by creator and shared across all Direct Post clients |
| Pending inbox shares | At most 5 pending shares within any 24-hour period, per the upload-video reference; not a completed-post allowance |
| Video initialization, either flow | 6 requests per minute per user access token |
| Photo initialization | 6 requests per minute per user access token |
| Creator-info query | 20 requests per minute per user access token |
| Status fetch | 30 requests per 60 seconds per user access token |

Sources: [sharing guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines),
[upload-video reference](https://developers.tiktok.com/doc/content-posting-api-reference-upload-video),
[Direct Post video reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post),
[photo reference](https://developers.tiktok.com/doc/content-posting-api-reference-photo-post), and the creator-info
and status references above. The photo reference also lists `spam_risk_too_many_pending_share`, but describes its
five-pending-share limit in terms of videos; it doesn't publish a separate photo allowance.

Don't promise every creator 15 posts, interpret 6 requests per minute as 6 allowed posts, or treat a second app as a
fresh creator allowance. Handle `spam_risk_too_many_posts`, `reached_active_user_cap`,
`spam_risk_too_many_pending_share` and `rate_limit_exceeded` as different conditions. Keep the attempt's publish ID
and check its status before considering a resend: a lost response doesn't prove TikTok received nothing.

## What Flaghand does today

As of October 26, 2026, **Flaghand's TikTok inbox drafts are in beta. Public Direct Post waits for TikTok's audit.**
This describes merged code and the [published API](https://app.flaghand.com/api/v1/openapi.json), not proposed features
or open pull requests. Private Direct Post testing remains subject to the unaudited restrictions above; it isn't
public publishing access or a promise of audit approval.

- **Prepare photos or video.** The API, CLI and MCP accept `tiktok_photo` and `tiktok_video` drafts. Photo posts can
  use uploaded images or a slideshow drawn by Flaghand's shared renderer. The free
  [TikTok slideshow maker](/tiktok-slideshow-maker) exports images; it doesn't publish to TikTok.
- **Send to the inbox, with the owner's approval.** `post_mode: "inbox"` requests this route; it isn't the draft's
  default. The agent drafts, uploads, checks and requests approval. Only the owner approves the exact snapshot in
  Flaghand with their passkey before Flaghand sends anything. The creator then finishes and publishes in TikTok.
- **Report the handoff honestly.** An `inbox` job means delivered to the TikTok inbox, not published. A `processing`
  job isn't finished. Flaghand follows TikTok's status; that is not a comparison of a live TikTok post against the
  approved preview.
- **Keep public Direct Post separate.** The merged implementation has owner-selected privacy and interactions,
  disclosure, consent and fresh creator-info checks. Its configured audit posture is still `unaudited`: private
  accounts and `SELF_ONLY` only. It doesn't offer public Direct Post before the audit, or TikTok scheduling.

[Flaghand and TikTok](/tiktok) explains the connection, permissions and data handling. The
[TikTok API reference](https://app.flaghand.com/docs/tiktok) and [slideshow reference](https://app.flaghand.com/docs/slideshows) document the merged
formats. Agent tokens cannot approve, schedule or post; the [agent guide](https://app.flaghand.com/docs/agents) explains that boundary.
Flaghand is in early access. [Get access](/schedule).

[All guides](/docs/guides.md)
