July 1, 2026
How to Post to TikTok with an API: Developer Guide
STOP!
Want an easy way to post on TikTok with an API?
Just use our unified social media API. One reliable endpoint for TikTok and 9 more platforms. Integrate in minutes and cut development time by 90%.
-
We manage auth, rate limits, and breaking API changes
-
Automatic retries and durable job queues
-
Fully white-labeled. Your audience never sees Mallary
-
Officially verified and approved to post on all platforms
fetch('https://mallary.ai/api/v1/post', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
platforms: ["tiktok"],
message: "Check out our new product!",
media: [{ url: "https://files.mallary.ai/launch-video.mp4" }],
comments_under_post: ["comment 1", "comment 2", "comment 3"],
auto_reply_enabled: true,
})
})
Your PM asks for “TikTok publishing” and it sounds like a small feature. Add OAuth, upload a video, publish it, done.
Then you start building it and realize the hard part isn't the first API call. It's everything around it. Scope approval. UX review. stateful uploads. asynchronous processing. status polling that can't be naïve. retry behavior that won't duplicate posts. token handling that won't strand jobs halfway through a publish cycle.
That's the gap in most guides about how to post to TikTok with an API. They show the happy path. Production systems live in the unhappy path.
Table of Contents
- Why Posting to TikTok with an API is Deceptively Hard
- The Official TikTok API Workflow Deconstructed
- A Step-by-Step Guide to Direct Publishing with Code
- Production Best Practices and Critical Pitfalls
- The Simpler Path How to Post to TikTok with Mallary.ai
- Frequently Asked Questions About the TikTok Content API
Why Posting to TikTok with an API is Deceptively Hard
The most common failure mode is underestimating the work. A team budgets for “an integration” and discovers they're building a small workflow engine.
One developer handles OAuth. Another wires up upload endpoints. QA tests a few videos and gets a green light. Then real users arrive and the edge cases start. One token expires during polling. Another upload succeeds but the post never leaves processing. A third account can authenticate, but the app still can't publish because the product flow doesn't satisfy TikTok's review expectations.
The hidden problem is that TikTok publishing is not a single request. It's a chain of dependent steps with state that has to survive network failures, restarts, and platform validation.
Practical rule: If your implementation stores publish state only in memory, it isn't production ready.
The hard parts tend to cluster in four places:
- Approval friction: Getting a developer app connected to real publishing access is harder than basic setup suggests.
- OAuth and consent flow: Reviewers care about how consent is presented, not only whether tokens work.
- Upload orchestration: You don't publish a video by sending one JSON payload. You initialize, upload media, then confirm final status asynchronously.
- Operational reliability: Jobs need retries, backoff, token refresh, and idempotent handling.
A lot of developers searching for how to post to TikTok with an API are already in this exact situation. The code “works” in a narrow test. The system doesn't hold up under actual usage.
That's why the official path matters. It shows the platform contract. But if you're shipping inside a product with deadlines, you also need to judge whether maintaining that contract yourself is worth it.
The Official TikTok API Workflow Deconstructed
A TikTok publish job usually fails long before the video upload. The first blocker is often review. The second is state management.

Start with approval, not code
Direct publishing starts with app approval, the right scopes, and a product flow that TikTok will accept. video.publish is only part of the requirement. Teams also run into UX review issues because TikTok evaluates how consent, account connection, and publishing behavior appear in the product, not only whether the API calls succeed.
That review step is where many integrations stall. A public UX compliance discussion for Direct Post shows how often smaller apps get blocked on product expectations rather than raw implementation mistakes.
If you want the architecture view before writing the upload pipeline, this Mallary overview of the TikTok API workflow is a useful reference. It explains the system design questions that usually surface after the first prototype.
For products that also need scheduling, the API work and the user workflow should be designed together. This guide to effective TikTok post scheduling is helpful for thinking through the application layer around publishing, approvals, and job timing.
The workflow is sequential and stateful
The official flow has five distinct stages:
- Register the app and get user authorization
- Call
creator/infoto validate the creator account - Initialize a publish job
- Upload the video or give TikTok a fetchable media URL
- Poll until the publish job reaches a terminal state
creator/info is easy to skip in a prototype and painful to ignore in production. TikTok uses it to confirm account eligibility and return account-level publishing constraints, including limits that affect whether a given upload should even start.
The publish request is a job lifecycle
Developers often describe TikTok publishing as "posting a video." Operationally, it is closer to creating and managing a job with multiple dependent steps. You initialize the job, get back an upload_url and publish_id, complete media transfer, then keep checking status until TikTok finishes processing.
That design creates real trade-offs:
| Choice | What it does | Where it hurts |
|---|---|---|
| FILE_UPLOAD | Your backend sends the video bytes directly | Larger request handling, temp storage, retry complexity |
| PULL_FROM_URL | TikTok fetches media from your hosted asset | You need stable hosting and domain setup that TikTok accepts |
| Direct polling | Your system tracks async completion itself | You need durable workers, backoff rules, and idempotent status updates |
This is the official contract. It works, but it pushes a lot of operational burden onto your app. If you're building this yourself, plan for failed uploads, stuck processing states, expired tokens during polling, and support tickets from users who only see "posted soon" while the job is still unresolved.
A Step-by-Step Guide to Direct Publishing with Code
A prototype can upload a TikTok video in an afternoon. A production integration takes longer because the hard parts are not the two endpoint calls. They are token lifecycles, state recovery after worker failures, and explaining to users why an upload that returned 200 is still not visible.

Get the app and auth layer right first
Start with the parts that are expensive to change later. Your app needs the right scopes, your OAuth flow needs to match what TikTok reviewers expect, and your backend needs a persistent job model before the first upload goes live. Teams that skip this usually end up rewriting the integration after the first round of support tickets.
If your product includes planned publishing, this guide to effective TikTok post scheduling is a useful companion because it covers workflow decisions outside the raw upload pipeline.
Persist at least these records:
- User token state: access token, refresh metadata, and last successful refresh time
- Publish job record: local job ID, TikTok
publish_id, requested caption, media source, and current state - Retry metadata: attempt count, next retry time, and last error payload
If you are building a full scheduling layer around direct publishing, this guide to scheduling TikTok videos is a useful reference for the application design around the upload flow.
Initialize the upload
The first API call is /v2/post/publish/video/init/. It returns two values your system must persist immediately: upload_url and publish_id.
That sounds simple. The trade-off is in the upload mode you choose. FILE_UPLOAD gives you direct control, but your backend now owns file transfer, retry logic, and request sizing. PULL_FROM_URL removes the byte transfer from your app, but only works well if your media hosting and domain verification are already in place.
cURL example
curl -X POST "https://open.tiktokapis.com/v2/post/publish/video/init/" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_info": {
"source": "FILE_UPLOAD",
"video_size": 30567100,
"chunk_size": 30567100,
"total_chunk_count": 1
},
"post_info": {
"title": "API upload test"
}
}'
Node.js example
const response = await fetch("https://open.tiktokapis.com/v2/post/publish/video/init/", {
method: "POST",
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
source_info: {
source: "FILE_UPLOAD",
video_size: fileSize,
chunk_size: fileSize,
total_chunk_count: 1
},
post_info: {
title: caption
}
})
});
const data = await response.json();
const uploadUrl = data.data.upload_url;
const publishId = data.data.publish_id;
Python example
import requests
payload = {
"source_info": {
"source": "FILE_UPLOAD",
"video_size": file_size,
"chunk_size": file_size,
"total_chunk_count": 1
},
"post_info": {
"title": caption
}
}
resp = requests.post(
"https://open.tiktokapis.com/v2/post/publish/video/init/",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json=payload
)
data = resp.json()
upload_url = data["data"]["upload_url"]
publish_id = data["data"]["publish_id"]
Upload the file bytes
With FILE_UPLOAD, TikTok expects a PUT request to the returned upload_url. Your request headers matter. The Content-Type must match the asset, and the Content-Range must match the exact byte boundaries of the upload.
cURL example
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
-H "Content-Range: bytes 0-30567099/30567100" \
--data-binary "@video.mp4"
Node.js example
import fs from "fs";
const videoBuffer = fs.readFileSync("./video.mp4");
const totalSize = videoBuffer.length;
await fetch(uploadUrl, {
method: "PUT",
headers: {
"Content-Type": "video/mp4",
"Content-Range": `bytes 0-${totalSize - 1}/${totalSize}`
},
body: videoBuffer
});
Python example
with open("video.mp4", "rb") as f:
video_bytes = f.read()
total_size = len(video_bytes)
upload_resp = requests.put(
upload_url,
headers={
"Content-Type": "video/mp4",
"Content-Range": f"bytes 0-{total_size - 1}/{total_size}"
},
data=video_bytes
)
This is one of the spots where developer time disappears. A local test with a small .mp4 can pass, then fail in production because a proxy rewrites headers, a worker truncates a temporary file, or the upload job is retried without resetting byte ranges. Those bugs are tedious to reproduce.
For teams already storing media in cloud buckets, PULL_FROM_URL is usually the cleaner path. TikTok fetches the asset directly. The catch is that your video domain must already be accepted, and that requirement tends to surface late if nobody tested with production hosting.
A managed abstraction such as Mallary.ai is faster here because it removes most of the transport concerns. Instead of maintaining upload workers, storage handoffs, and state transitions yourself, you hand off a simpler publish request and let the provider absorb the ugly parts.
A short demo can help if you want to compare the endpoint flow with a live walkthrough:
Poll until the post is actually live
After the upload completes, the job is still in progress. Your app needs to check status with the returned publish_id and treat the result as asynchronous state, not as an immediate post confirmation.
cURL example
curl -X POST "https://open.tiktokapis.com/v2/post/publish/status/fetch/" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"publish_id": "YOUR_PUBLISH_ID"
}'
Node.js example
async function fetchPublishStatus(accessToken, publishId) {
const resp = await fetch("https://open.tiktokapis.com/v2/post/publish/status/fetch/", {
method: "POST",
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ publish_id: publishId })
});
return resp.json();
}
Python example
def fetch_publish_status(access_token, publish_id):
resp = requests.post(
"https://open.tiktokapis.com/v2/post/publish/status/fetch/",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json={"publish_id": publish_id}
)
return resp.json()
Many direct integrations often start to feel heavier than expected. You need a background worker, persisted retry state, sensible backoff, and user-facing status messages that do not promise success too early. If the token expires during polling, or your worker restarts mid-job, your database has to tell you exactly what happened and what to retry.
That is the official path. It works, and plenty of teams ship it. The smarter path for production is to avoid owning every operational edge case yourself unless TikTok publishing is core infrastructure for your product.
Production Best Practices and Critical Pitfalls
Getting one video through the pipeline is straightforward. Operating the pipeline for real users is where most integrations get expensive.

Why simple polling fails
TikTok's async publishing status must be polled, but naïve loops will hit the 6 requests per minute per access token limit. Durable job queues, exponential backoff, and token refresh logic are required to avoid dropped posts, as described in this production-oriented TikTok polling guide.
That limit changes your architecture.
A while status != SUCCESS loop looks harmless in local testing. In production, it creates three problems:
- Bursting into limits: Multiple pending jobs for the same user quickly collide.
- Losing work on restarts: If the process dies, in-memory polling state disappears.
- Breaking on expired auth: Polling can outlive the access token that started the upload.
Treat post publication as a background job with persisted state, not as a synchronous request-response action.
Patterns that hold up in production
The teams that keep these integrations stable usually converge on the same patterns.
| Pattern | Why it matters |
|---|---|
| Durable queues | Jobs survive worker restarts and deploys |
| Exponential backoff | Reduces rate-limit collisions and noisy retries |
| Idempotency keys | Prevents duplicate publish attempts after partial failure |
| Token refresh before critical steps | Avoids mid-flight auth failures |
You don't need exotic infrastructure. BullMQ, Celery, Sidekiq, or any queue with delayed retries can handle the shape of the problem. What matters is the job contract.
A good job should persist:
- External identifiers such as
publish_id - Lifecycle state such as initialized, uploaded, polling, success, failed
- Last recoverable checkpoint so a retry resumes work rather than restarts blindly
There's also a documentation problem within many teams. Publishing flows fail unnoticed when implementation notes live in one engineer's head. If you're formalizing runbooks for auth refresh, retry semantics, and queue behavior, this piece on how to ship faster with clearer documentation is worth sharing with the team.
“Successful integration” means your support team can explain any failed post from logs and job history without reading source code.
That's the standard to build for.
The Simpler Path How to Post to TikTok with Mallary.ai
There's a point where direct integration stops being a feature and starts becoming platform maintenance. That's usually when teams look for an abstraction layer.

Direct integration versus managed abstraction
A managed API changes the developer job. Instead of owning TikTok's app review friction, upload choreography, and polling system yourself, you call a higher-level endpoint and let the provider own the fragile parts.
For TikTok specifically, Mallary's TikTok platform page presents that model as a unified publishing layer rather than a raw endpoint wrapper. The practical difference is that your app deals with post intent, while the platform deals with media validation, token handling, retries, and status management behind the scenes.
Here's the trade-off in plain terms:
| Concern | Direct TikTok integration | Managed API layer |
|---|---|---|
| OAuth handling | You build and maintain it | Provider abstracts most of it |
| Upload sequence | You orchestrate init, PUT, polling | One higher-level call |
| Retry semantics | Your responsibility | Usually built in |
| Rate-limit strategy | Your workers must respect it | Abstracted operationally |
| Platform drift | You monitor API changes | Provider absorbs updates |
If your product is TikTok-only and your team wants full native control, direct can make sense. If TikTok is one feature among many, the maintenance burden is usually the deciding factor.
What the developer experience looks like
With a direct build, you typically write code for:
- auth flow and token storage
- creator metadata checks
- upload init requests
- binary upload transfer
- asynchronous polling
- retry and recovery logic
- support tooling for stuck jobs
With a managed layer, your code can stay focused on business logic. Receive a user request, send a media URL plus caption, store the resulting job reference, and subscribe to status updates if the provider supports them.
That isn't magic. It's just moving complexity to the part of the stack built to carry it.
The main question isn't whether you can post to TikTok with an API directly. You can. The core question is whether your team wants to spend its time maintaining a specialized publishing pipeline or shipping the user-facing parts of the product.
Frequently Asked Questions About the TikTok Content API
Can I schedule posts with the official API
Treat scheduling as your responsibility, not TikTok's.
In practice, that means your app should hold the publish job, preflight the media well before the target time, and start the posting pipeline early enough to absorb token refreshes, upload time, and moderation or processing delays. Teams that promise exact publish times usually get into trouble when they trigger the whole flow at the last minute.
Build for a scheduling window, not a single timestamp.
What breaks direct publishing most often
Two failure points show up again and again in production. The first is account-specific media limits. The second is rate pressure on upload initialization for a single user token.
Handle both before you start moving bytes.
- Validate duration up front: fetch the creator's posting constraints, compare them to the file locally, and reject early if the video is too long for that account.
- Throttle init calls per user: if one creator queues multiple posts, serialize or rate-limit those init requests so your workers do not trip over the same token window.
- Surface the reason clearly: “video exceeds account limit” is actionable. “publish failed” creates support tickets.
This is one of the places where the happy-path sample code stops being useful. Real systems need queue discipline, per-account concurrency control, and failure messages your support team can work with.
What should the review demo actually show
A lot of TikTok integrations stall at review because the problem is not the API call. It is the UX evidence.
Reviewers need to see a flow where the user understands three things clearly: which TikTok account is connected, what content is about to be published, and what action confirms consent. If those details are vague or buried, approval gets harder.
A review demo should show:
- Visible account identity: the connected TikTok account should be obvious on screen.
- Clear publishing intent: the user should see the video, caption, or post summary before confirming.
- Explicit consent language: the UI should make it clear that the action publishes to TikTok, not just “continues” or “connects.”
- No hidden assumptions: avoid generic buttons that skip over what the user is authorizing.
I have seen technically correct implementations get delayed here because the demo looked ambiguous. Product copy and UI screens matter as much as request signatures.
How should I handle larger uploads
Run uploads in background workers and persist state after every meaningful step. Do not tie a large media transfer to a single web request and hope it finishes cleanly.
Store upload identifiers as soon as TikTok returns them. Track checkpoints so retries can resume with context instead of restarting blindly. If you use hosted media, PULL_FROM_URL can reduce backend transfer work, but only after domain verification is already in place and reliable.
Keep your status model honest. “Upload complete” and “published” are different states, and your UI should reflect that. The gap between those two states is where async polling, retries, and support issues usually show up.
If you need TikTok publishing in a product and do not want to own the full approval, upload, retry, and polling workload yourself, Mallary.ai is one option to evaluate. It gives teams a developer-focused layer for social publishing so they can spend more time on product workflows and less time maintaining platform-specific infrastructure.