Skip to main content
Back to all posts

TikTok Direct Posting API: Step-by-Step Setup Tutorial (2026)

·7 min read·Yoav Mendelson
tiktok apitiktok direct posting apicontent posting apitiktok audittutorial2026

This is a step-by-step tutorial for shipping TikTok's Direct Posting API: the gauntlet between a fresh developer account and a working integration that publishes public videos straight to a real creator's profile.

If you're integrating the TikTok Content Posting API and someone told you it'd take a weekend, they were wrong. Direct posting (videos that publish straight to a public profile instead of dumping into the creator's inbox) is the strictest gate of any major social API. The same five or six things kill teams' timelines, and most of them are review queues you can't speed up.

This is the actual list, in the order it'll bite you.

1. Asset URLs have to live on a verified domain

TikTok's /v2/post/publish/video/init/ endpoint accepts a PULL_FROM_URL source. The URL has to be on a domain you've verified in the TikTok Developer Portal with a tiktok-developers-site-verification meta tag or DNS record.

If your videos sit on a CDN like S3 or Cloudflare R2, you need to verify that exact host. Pre-signed URLs from an unverified bucket get rejected with url_ownership_unverified before the upload even starts.

If you control DNS for the CDN, verify it directly. If you don't, proxy the assets through a domain you do own. Do this first. Skip it and every other test fails for the wrong reason and you waste a day chasing the wrong bug.

2. You can't develop against it locally

The OAuth redirect URI has to be HTTPS, and TikTok rejects localhost, 127.0.0.1, and *.local. So the moment you start the OAuth flow, you need a public HTTPS URL pointing at your laptop.

That means localtunnel or Cloudflare Tunnel during dev. Every time your tunnel URL changes you also have to update the redirect URI inside the TikTok app settings.

npx localtunnel --port 3000 --subdomain my-tiktok-dev
# Take the https URL it prints, paste it into TikTok's app settings
# under "Redirect URI", then add the same URL to your OAuth start handler

Two things that saved me hours: pass a fixed --subdomain so the URL is stable across restarts, and put the redirect URI in an env var so it's not hardcoded in three places when the tunnel rotates.

3. Every review takes days, with no SLA

Three separate things go through TikTok review, each in its own queue:

  1. The base sandbox app, so you can leave sandbox and serve real users.
  2. Each scope you add (video.publish, video.upload, user.info.basic).
  3. The Content Posting API direct-post permission, which is its own beast (next section).

Each one takes anywhere from two days to two weeks. There's no published SLA. If they request changes, the clock resets. The reviews run in serial too: a rejection on the base app blocks everything downstream.

The one real lever you have is batching. Submit every scope you think you might need on day one. Adding a scope later means another full review cycle, which is how a "small change" turns into another week of waiting.

4. Direct posting is a separate review most people miss

This is the one that catches teams late. Passing the base app review doesn't let you publish public videos. It just lets you upload to the creator's TikTok inbox (SEND_TO_USER_INBOX), where the creator manually finishes posting inside the TikTok app.

To publish directly to a public timeline, you have to submit a second review specifically for the Content Posting API audit. Before that audit passes, every direct post is forced to SELF_ONLY, meaning only the connected creator can see the video. Your end users will think your integration is broken.

The audit submission asks for a recorded demo of your full posting flow, your privacy policy URL, and proof that the integration belongs inside a finished product. Which leads to the next blocker.

5. It has to be a real product, not a prototype

TikTok rejects audit submissions for apps that look like internal tools, side projects, or demos. The reviewer will open your privacy policy, your landing page, and the URLs in your app description. If they don't see a working product with real users (or at minimum a credible, deployed signup flow), they bounce the submission.

A non-exhaustive list of what reviewers actually check:

  • A reachable, branded landing page
  • A privacy policy that mentions TikTok specifically and how user data is handled
  • Terms of service
  • A real signup or login flow
  • A demo video showing the integration end-to-end, not just an API call in Postman

Building all of this just to test posting is a lot of yak shaving. Most teams underestimate it by a factor of three.

6. The required UX is non-negotiable

Once you're audited, you still have to render TikTok's posting UI the way they specify it. This is the part you can't fake, because the reviewer watches your demo video and checks.

The privacy picker has to be selected by the user, not pre-selected for them. You call /v2/post/publish/creator_info/query/ per creator, read privacy_level_options, and render whatever comes back as a list the user picks from. Default-selecting PUBLIC_TO_EVERYONE will get you bounced. And the allowed levels actually vary per creator: a private account won't have PUBLIC_TO_EVERYONE available at all, so hardcoding the four standard levels also gets you rejected.

Comment, duet, and stitch toggles work the same way. Whether each one is even available is a property of the creator's account, not your UI. comment_disabled, duet_disabled, and stitch_disabled come back from creator_info. If a creator has duet off at the account level, your toggle has to be disabled in the UI to match.

Commercial content disclosure is a forced flow with its own rules:

  • Toggling "Your brand" or "Branded content" must reveal TikTok's exact disclosure text. Not a paraphrase.
  • The same flow has to link to TikTok's music usage confirmation page.
  • Branded content forces the post public, so the privacy picker has to remove SELF_ONLY when that toggle is on.

And once a post is uploaded, that's it. There's no edit endpoint. A user who typoed the caption has to delete the post and re-upload.

Get any of this wrong and your audit submission comes back with a one-line note that doesn't tell you which rule you broke. Re-record the demo, resubmit, wait another week.

What this adds up to

Realistic schedule for shipping TikTok direct posting from scratch, assuming you do everything right the first time:

Week 1 is plumbing: domain verification, OAuth with a tunnel, upload-to-inbox working end to end. Week 2 is building the product surface TikTok needs to see (landing page, privacy policy, signup) and submitting the base app review. Week 3 is the response on that review, fixing whatever they flagged, and resubmitting. Week 4 is the Content Posting audit submission with the demo video. Week 5 or 6 is the audit response, which almost always comes back with revision requests on the UX. Week 6 or 7 is the resubmit, and finally direct posting.

That's the fast path. The slow path is months.

The shortcut

If you don't want to run this gauntlet, PostPeer is already audited. You hit one endpoint with a video URL and a creator ID, and the publish goes through under our app's permissions. Draft mode works on the free tier without you touching the TikTok developer portal. Direct public posting works the moment a creator connects their account, no audit on your side.

Step-by-step is in the TikTok posting guide. If you want to see the API live before writing any code, the free TikTok scheduler runs on the same endpoint.

Either path beats six weeks of waiting on TikTok's review queue.