# How to Post to TikTok via API (Content Posting API)

Post to TikTok via API with the Content Posting API: scopes, creator info, FILE_UPLOAD vs PULL_FROM_URL, status checks, privacy rules, and the audit.

Canonical page: https://www.tryadeli.com/blog/post-to-tiktok-via-api
Last updated: 2026-10-05

By Mika Reyes, Co-founder, Adeli. Published 2026-10-05.

## The short answer

You post to TikTok via API with TikTok's Content Posting API. Your app gets the video.publish scope, queries the creator's info, initializes the post with FILE_UPLOAD or PULL_FROM_URL, sends or hands over the video, and polls the publish status. Until TikTok audits the app, every post is private. Adeli publishes to TikTok through one API, without your own TikTok app or audit.

**To post to TikTok via API, you use TikTok's Content Posting API**: query the creator's info, initialize the post, upload the video (or let TikTok pull it from your URL), then poll until it publishes. The API calls are the straightforward part. Whether anyone besides the creator sees the post depends on TikTok's privacy rules and its audit.

This guide covers the flow call by call, with the curl requests from TikTok's own docs. If you haven't picked a portal yet, read [TikTok API for Business vs TikTok for Developers](https://www.tryadeli.com/blog/tiktok-api-for-business-vs-developers) first.

## Can you post to TikTok via API?

**Yes.** The [Content Posting API](https://developers.tiktok.com/doc/content-posting-api-get-started) on TikTok for Developers posts videos and photo posts to the account of any TikTok user who authorized your app.

Until your app passes TikTok's Content Posting API audit, **everything it posts is private**. TikTok's [get-started guide](https://developers.tiktok.com/doc/content-posting-api-get-started) says content from unaudited clients "will be restricted to private viewing mode." You can build and test the whole flow before the audit, but you can't ship it to real users.

TikTok API for Business has its own publishing endpoint in the Accounts API. That one only publishes public video posts, and it's covered in the [portal comparison](https://www.tryadeli.com/blog/tiktok-api-for-business-vs-developers).

## Direct post or upload to inbox: which one do you need?

**Direct post** publishes the video to the creator's profile. **Upload to inbox** sends it to their TikTok drafts, and the creator finishes and posts it in the TikTok app.

| | Direct post | Upload to inbox (draft) |
| --- | --- | --- |
| Scope | `video.publish` | `video.upload` |
| Init endpoint | `/v2/post/publish/video/init/` | `/v2/post/publish/inbox/video/init/` |
| Caption, privacy, interaction settings | Set by your app, in `post_info` | Set by the creator in TikTok |
| Who presses "post" | Your app | The creator, from an inbox notification |
| Extra limit | About 15 posts per creator per day | At most 5 pending shares in 24 hours |
| Docs | [Direct Post reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post) | [Upload reference](https://developers.tiktok.com/doc/content-posting-api-reference-upload-video) |

Pick direct post if your product publishes on the user's behalf, like a scheduler or an AI content tool. Pick upload to inbox if the creator should review and edit in TikTok before anything goes live. TikTok's [upload reference](https://developers.tiktok.com/doc/content-posting-api-reference-upload-video) says you should tell users to tap the inbox notification to finish the post.

The rest of this guide follows direct post. The upload flow uses the same media transfer step and skips `post_info`.

## What do you need before you start?

TikTok's [get-started guide](https://developers.tiktok.com/doc/content-posting-api-get-started) lists these prerequisites:

- **A registered app** on TikTok for Developers, with the **Content Posting API** product added.
- **Direct Post enabled** in the Content Posting API configuration for your app.
- **The `video.publish` scope**, approved for your app and authorized by the TikTok user through Login Kit.
- **The user's access token and open ID**, from that OAuth flow.
- **A video file** (MP4 with H.264 is the recommended pairing) or a video URL on a domain you've verified.

Getting the app and the scope approved is its own process, covered in [how to get TikTok API access](https://www.tryadeli.com/blog/how-to-get-tiktok-api-access). This post assumes you already have a working access token.

## Step 1: Query the creator's info

Before every post, call **`creator_info/query`**. It tells you which privacy levels this creator can use, whether they've turned off comments, Duets, or Stitches, and the longest video they're allowed to post.

```bash
curl --location --request POST 'https://open.tiktokapis.com/v2/post/publish/creator_info/query/' \
--header 'Authorization: Bearer act.example12345Example12345Example' \
--header 'Content-Type: application/json; charset=UTF-8'
```

The [creator info reference](https://developers.tiktok.com/doc/content-posting-api-reference-query-creator-info) returns:

- **`creator_nickname` and `creator_username`.** Show the nickname in your UI so the user knows which account they're posting to.
- **`privacy_level_options`.** The only privacy values you're allowed to send for this creator. A private account gets a different list from a public one.
- **`comment_disabled`, `duet_disabled`, `stitch_disabled`.** If one is `true`, grey out that toggle in your UI.
- **`max_video_post_duration_sec`.** Reject videos longer than this before you upload them.

The same call returns `spam_risk_too_many_posts` when the creator has hit their daily post cap, so you can stop there instead of uploading a video that can't be posted.

## Step 2: Initialize the post

**`POST /v2/post/publish/video/init/`** creates the post and returns a **`publish_id`**. You send the caption and settings in `post_info`, and tell TikTok how the video is coming in `source_info`.

```bash
curl --location 'https://open.tiktokapis.com/v2/post/publish/video/init/' \
--header 'Authorization: Bearer act.example12345Example12345Example' \
--header 'Content-Type: application/json; charset=UTF-8' \
--data-raw '{
  "post_info": {
    "title": "this will be a funny #cat video on your @tiktok #fyp",
    "privacy_level": "MUTUAL_FOLLOW_FRIENDS",
    "disable_duet": false,
    "disable_comment": true,
    "disable_stitch": false,
    "video_cover_timestamp_ms": 1000
  },
  "source_info": {
      "source": "FILE_UPLOAD",
      "video_size": 50000123,
      "chunk_size":  10000000,
      "total_chunk_count": 5
  }
}'
```

Other fields to get right, from the [Direct Post reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post):

- **`title`** is the caption, hashtags and mentions included, up to **2,200 UTF-16 runes**.
- **`privacy_level`** must be one of the `privacy_level_options` from step 1, or the request fails with `privacy_level_option_mismatch`.
- **`brand_content_toggle` and `brand_organic_toggle`** mark paid partnerships and self-promotion. **`is_aigc`** labels AI-generated content.

For `FILE_UPLOAD`, the response includes an **`upload_url` that's valid for one hour**. For `PULL_FROM_URL`, there's no upload URL, because TikTok fetches the file.

## Step 3: Upload the video to TikTok

There are two ways to get the video to TikTok: push the bytes yourself with **`FILE_UPLOAD`**, or have TikTok download it with **`PULL_FROM_URL`**. The [media transfer guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide) sets the rules for both.

| | `FILE_UPLOAD` | `PULL_FROM_URL` |
| --- | --- | --- |
| How it works | You PUT the file to `upload_url` | TikTok downloads from your `video_url` |
| Setup | None | Verify the domain or URL prefix in the developer portal first |
| Size rules | Chunks of 5–64 MB, final chunk up to 128 MB, 1 to 1,000 chunks | The URL must use HTTPS, return no redirects, and stay reachable for up to an hour |
| Best for | Files on your server or in memory | Files already in object storage or on a CDN you control |

For `FILE_UPLOAD`, send each chunk with a `Content-Range` header:

```bash
curl --location --request PUT 'https://open-upload.tiktokapis.com/upload/?upload_id=67890&upload_token=Xza123' \
--header 'Content-Range: bytes 0-30567099/30567100' \
--header 'Content-Length: 30567100' \
--header 'Content-Type: video/mp4' \
--data '@/path/to/file/example.mp4'
```

`total_chunk_count` is **`video_size` divided by `chunk_size`, rounded down**. The leftover bytes go in the last chunk, which is why it's allowed to be bigger than the rest.

For `PULL_FROM_URL`, swap the `source_info` block in step 2 for:

```json
"source_info": {
  "source": "PULL_FROM_URL",
  "video_url": "https://example.verified.domain.com/example_video.mp4"
}
```

A URL on a domain you haven't verified returns `url_ownership_unverified`. Serve the file from a domain or URL prefix you've verified.

Whichever source you use, the video has to meet TikTok's specs: **MP4, WebM, or MOV, up to 4 GB, 23 to 60 FPS, 360 to 4,096 pixels on each side**, and no longer than the creator's `max_video_post_duration_sec`.

## Step 4: Check the post status

Poll **`POST /v2/post/publish/status/fetch/`** with the `publish_id` until the status is `PUBLISH_COMPLETE` or `FAILED`. A 200 from the init call only means TikTok accepted the job.

```bash
curl --location 'https://open.tiktokapis.com/v2/post/publish/status/fetch/' \
--header 'Authorization: Bearer act.example12345Example12345Example' \
--header 'Content-Type: application/json; charset=UTF-8' \
--data '{
    "publish_id": "v_pub_url~v2.123456789"
}'
```

The [status reference](https://developers.tiktok.com/doc/content-posting-api-reference-get-video-status) lists five states: `PROCESSING_UPLOAD`, `PROCESSING_DOWNLOAD`, `SEND_TO_USER_INBOX`, `PUBLISH_COMPLETE`, and `FAILED`. A failure comes with a `fail_reason` such as `file_format_check_failed`, `duration_check_failed`, or `spam_risk`.

`PUBLISH_COMPLETE` doesn't mean the post is public yet. The `publicaly_available_post_id` field (TikTok's spelling) only appears **after the post is public and has cleared TikTok moderation**. If you'd rather not poll, the Content Posting webhooks send `post.publish.complete`, `post.publish.failed`, and `post.publish.publicly_available` events.

## What privacy levels can you set, and what does TikTok require?

`privacy_level` takes `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, or `SELF_ONLY`, **limited to whatever `privacy_level_options` returned for that creator**. TikTok's [Content Sharing Guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines) also set rules for the screen your users post from:

- **No default privacy.** The user picks a privacy level every time. Your UI can't preselect one.
- **Interaction toggles start off.** Comment, Duet, and Stitch are unchecked by default, and greyed out when the creator has disabled them.
- **Branded content can't be private.** If the user marks a post as Branded Content, `SELF_ONLY` is off the table.
- **Music Usage Confirmation.** The screen shows "By posting, you agree to TikTok's Music Usage Confirmation," with the Branded Content Policy added for branded posts.
- **Preview and a processing notice.** Users see the content before posting, and you tell them it can take a few minutes to show up on their profile.

These rules are what the audit checks. When we prepared our own Content Posting API submission, the demo video had to show every one of these controls on the posting screen, starting with nothing selected. A tour of the dashboard doesn't cover it.

## Why are my TikTok API posts private?

Your posts are private because **your app hasn't passed the Content Posting API audit**. Until it does, the [Content Sharing Guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines) apply three limits:

1. **Posts are `SELF_ONLY`.** Only the creator can see them.
2. **The posting account must be private.** A post to a public account fails with `unaudited_client_can_only_post_to_private_accounts`.
3. **Five users per 24 hours.** At most 5 users can post through your app in any 24-hour window.

Apply for the audit through TikTok's [Content Posting API application](https://developers.tiktok.com/application/content-posting-api). Passing it removes the private-only restriction but not the caps. Audited apps still get a daily quota of active posting users (`reached_active_user_cap`), and creators still hit a per-account limit that's typically **around 15 posts per day**.

## What rate limits apply when you post to TikTok via API?

Every Content Posting API limit is counted **per user access token, per minute**.

| Endpoint | Limit |
| --- | --- |
| `creator_info/query` | 20 requests per minute |
| `video/init` (direct post) | 6 requests per minute |
| `inbox/video/init` (upload) | 6 requests per minute |
| `status/fetch` | 30 requests per minute |

Sources: the [creator info](https://developers.tiktok.com/doc/content-posting-api-reference-query-creator-info), [Direct Post](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post), [upload](https://developers.tiktok.com/doc/content-posting-api-reference-upload-video), and [status](https://developers.tiktok.com/doc/content-posting-api-reference-get-video-status) references. Six inits a minute is more than one person posting by hand will use. A scheduler that releases a backlog for one account all at once can hit it, so space those posts out.

## Is there a faster way to post to TikTok via API?

**Adeli** publishes to TikTok through the same endpoint as Instagram, Facebook, YouTube, and X. Adeli maintains the TikTok developer app, goes through TikTok's review process, and handles token refresh for every connected account, so the audit and the private-only phase above aren't yours to run.

- **One request, every network.** Add TikTok to the platforms in a publish call. See the [posting API](https://www.tryadeli.com/social-media-posting-api).
- **Your users' own accounts.** Each user connects their own TikTok account, isolated from everyone else's.
- **Clear failures.** Every publish returns a per-platform status, plus a webhook when anything changes, so a TikTok failure doesn't block your other networks.
- **Scheduling built in.** Send a scheduled time instead of `publishNow` and the post waits in the queue.

Your first 3 connected accounts are free; [pricing](https://www.tryadeli.com/pricing) has the rest of the ladder. The [TikTok API page](https://www.tryadeli.com/product/tiktok) shows what Adeli supports on TikTok.

## Frequently asked questions

### Can you post to TikTok via API?

Yes. TikTok's Content Posting API, on TikTok for Developers, lets an approved app post videos and photos to the account of a user who authorized it. It can publish directly or upload to the user's TikTok inbox as a draft. Posts stay private until the app passes TikTok's Content Posting API audit.

### How do I upload a video to TikTok with the API?

Call the video init endpoint with source set to FILE_UPLOAD, then PUT the file to the upload_url TikTok returns, in chunks of 5 MB to 64 MB. Or set source to PULL_FROM_URL and pass an HTTPS URL on a domain you verified in the developer portal, and TikTok downloads the file itself.

### What is the TikTok Content Posting API?

The Content Posting API is TikTok's official API for publishing videos and photo posts to TikTok accounts. It lives on developers.tiktok.com, uses the video.publish scope for direct posts and the video.upload scope for drafts, and requires a separate audit before posts can be public.

### Can I post photos to TikTok via API?

Yes. Photo posts go through a separate endpoint, /v2/post/publish/content/init/, with media_type set to PHOTO and a list of image URLs from a verified domain. Unaudited apps can only post photos as SELF_ONLY.

## Related Adeli pages

- [TikTok API for Developers](https://www.tryadeli.com/product/tiktok.md): Publish, schedule, and read analytics for TikTok through one API. Adeli owns the TikTok developer app, token refresh, and review process. Free to start.
- [Social Media Posting & Scheduling API](https://www.tryadeli.com/social-media-posting-api.md): Adeli's social media posting and scheduling API publishes to Instagram, TikTok, YouTube, Facebook, and X in one request, now or at a set time. Free to start.
- [Adeli Pricing — priced per connected account](https://www.tryadeli.com/pricing.md): Your first 3 connected accounts are free, then $5 each for accounts 4–10, $3 each for 11–50, $2 each for 51–100, and $1 each up to 2,000. Above that, talk to sales.
- [All posts on the Adeli blog](https://www.tryadeli.com/blog.md)

## About the author

Mika Reyes is the CEO behind Adeli and a tech and AI content creator. She was previously co-founder and CEO of Parallax, which was acquired by Phantom, and a product lead at LinkedIn. She is a Forbes 30 Under 30 honoree.
