How do I post to TikTok with an API?
Send a multipart/form-data request to Upload-Post's POST https://api.upload-post.com/api/upload endpoint with your video file (or a public video URL), a user profile and platform[]=tiktok. Upload-Post runs its own approved TikTok app, so there's no developer application to register, no TikTok audit to pass, and no OAuth tokens to manage. You connect the TikTok account once in the dashboard and that's it. One caveat: TikTok posting needs a paid plan, it's not available on Free.
Steps
- Create an account at upload-post.com and generate an API key in the dashboard under API Keys (see Authentication).
- Connect a TikTok account to a profile at Manage Users. It's the normal TikTok login, no developer setup. For posting on behalf of your users, use white-label JWT connect links.
- Call the upload endpoint:
- cURL
- Python
- JavaScript
curl \
-H 'Authorization: Apikey your-api-key-here' \
-F 'video=@/path/to/your/video.mp4' \
-F 'title="Your Video Title"' \
-F 'user="test"' \
-F 'platform[]=tiktok' \
-X POST https://api.upload-post.com/api/upload
import requests
response = requests.post(
"https://api.upload-post.com/api/upload",
headers={"Authorization": "Apikey your-api-key-here"},
files={"video": open("/path/to/your/video.mp4", "rb")},
data={
"title": "Your Video Title",
"user": "test",
"platform[]": "tiktok",
},
)
print(response.json())
import fs from "node:fs";
const form = new FormData();
form.append("video", new Blob([fs.readFileSync("/path/to/your/video.mp4")]), "video.mp4");
form.append("title", "Your Video Title");
form.append("user", "test");
form.append("platform[]", "tiktok");
const response = await fetch("https://api.upload-post.com/api/upload", {
method: "POST",
headers: { Authorization: "Apikey your-api-key-here" },
body: form,
});
console.log(await response.json());
video also accepts a public URL instead of a file: -F 'video="https://example.com/videos/myvideo.mp4"'.
Useful TikTok parameters
All parameters are documented in the Upload Video reference. The most used ones:
| Parameter | What it does | Default |
|---|---|---|
tiktok_title | TikTok-specific caption (falls back to title). Max 2,200 chars for video. | title |
post_mode | DIRECT_POST publishes immediately; MEDIA_UPLOAD sends the video to the user's TikTok inbox/drafts. | DIRECT_POST |
privacy_level | PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY | PUBLIC_TO_EVERYONE |
disable_comment / disable_duet / disable_stitch | Turn off comments, duets or stitches | false |
cover_timestamp | Video frame (ms) to use as cover | 1000 |
is_aigc | Declare AI-generated content | false |
scheduled_date | ISO-8601 date to schedule the post | none |
first_comment / tiktok_first_comment | Auto-post a first comment under the published post (video and photos). Needs a reconnected account — see After publishing | none |
async_upload | Return immediately with a request_id and process in background (recommended) | false |
We recommend post_mode=MEDIA_UPLOAD (Draft): the video lands in the TikTok inbox and the user publishes it from the app, which typically performs better in TikTok's distribution. In Draft mode TikTok ignores title/privacy metadata sent via API.
TikTok photo slideshows
Post images (with optional automatic music) through the Upload Photos endpoint:
curl -X POST https://api.upload-post.com/api/upload_photos \
-H 'Authorization: Apikey your-api-key-here' \
-F 'photos[][email protected]' \
-F 'photos[][email protected]' \
-F 'title="Photo slideshow with music"' \
-F 'user="test"' \
-F 'platform[]=tiktok' \
-F 'auto_add_music=true'
What your account can do: capabilities
Not every TikTok connection accepts the same optional fields. GET /api/uploadposts/users returns a
capabilities array on the TikTok account of each profile —
music, location, cover_image, draft, profile_analytics, comments, trend_search and friends.
Read it and offer only what the connection actually supports, instead of sending a field and hoping.
Two of them, comments and trend_search, only appear once the account has been reconnected: TikTok
grants those permissions at the moment of connecting, so an account linked a while ago never received them.
That account keeps publishing exactly as before — nothing about its uploads changes — but the comment and
keyword-search endpoints answer 400 with error_code: "tiktok_reconnect_required" until its owner
reconnects it from Manage Users (or through a
white-label connect link, if your users never see our dashboard).
Sending an unsupported field is never fatal: the post is published and the response carries a warnings
array naming what was ignored.
After publishing: comments
A TikTok post is not the end of the job — the comments under it are where the reach is decided.
A first comment with the post. Send first_comment (or tiktok_first_comment to override it just for
TikTok) on the upload and it is posted under the video or photo carousel as soon as it goes live. It never
fails the publish: by the time it is attempted the post is already up, so anything that goes wrong is a
warnings entry with success: true. It is skipped, with a warning, for a post sent to drafts — there is
nothing published to comment on yet.
Reading and answering them. The Comments API takes platform=tiktok on all three
operations, with post_id = the video id the upload returned:
# List the comments on a video
curl 'https://api.upload-post.com/api/uploadposts/comments?platform=tiktok&user=test&post_id=7401234567890123456' \
-H 'Authorization: Apikey your-api-key-here'
# Reply to one of them (TikTok needs post_id even when replying)
curl -X POST https://api.upload-post.com/api/uploadposts/comments/create \
-H 'Authorization: Apikey your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{"platform":"tiktok","user":"test","post_id":"7401234567890123456","comment_id":"7401234567890999888","message":"Thanks! Guide in the bio."}'
Replies and moderation. Both stay inside the same Comments API. The replies under
a comment are the listing narrowed to a parent — add comment_id to
GET /comments — and the moderation verbs are one endpoint,
POST /comments/action, with action set to hide,
unhide, like, unlike, pin or unpin. Each verb carries its own inverse, so replaying a request can
never flip a comment back.
# The replies under one comment
curl 'https://api.upload-post.com/api/uploadposts/comments?platform=tiktok&user=test&post_id=7401234567890123456&comment_id=7401234567890999888' \
-H 'Authorization: Apikey your-api-key-here'
# Pin it to the top of the video
curl -X POST https://api.upload-post.com/api/uploadposts/comments/action \
-H 'Authorization: Apikey your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{"platform":"tiktok","user":"test","comment_id":"7401234567890999888","action":"pin","post_id":"7401234567890123456"}'
A comment you just wrote takes about 10 seconds to show up in a listing — TikTok indexes it asynchronously, so an empty list right after creating one is not a failure.
All of this needs the comments capability, i.e. a reconnected account.
Before publishing: what to post about
One endpoint, GET /suggestions, turns "write something about instant cameras"
into a caption aimed at demand that exists:
type=keywords— the terms people actually type on TikTok around your seed word, with their search volume. Needstrend_search, i.e. a reconnected account.type=hashtags— the tags to pair with that keyword and how many views each one carries, optionally ranked per country (country_code) and language. Needsprofile_analytics, which any recent connection has.
After publishing: how it did
Get Analytics gives you the numbers, and on TikTok it gives you a lot more than
four counters. Everything below needs profile_analytics, which any recent connection has:
GET /post-analytics— per post, on top of views, likes, comments and shares:reach,favorites,new_followers,profile_views,full_video_watched_rate,average_time_watched,total_time_watched, theretentioncurve second by second,impression_sources(For You, Search, Follow, Personal Profile, Sound, Direct Message, Others) andaudience_types. What TikTok did not report is omitted, not zeroed.GET /audience— who follows the account (countries, cities, ages, genders), daily followers gained and lost, profile actions, andactivity_by_hour: how many of your followers are online in each hour of the day. That last one is the honest answer to "when should I publish", and it comes from your own audience rather than a generic best-time table. Window: up to 60 days, ending yesterday at the latest, trimmed automatically — read therangethat comes back.- The same call with
benchmark_categoryadds the averages of your content category, so a 6% engagement rate stops being a number and becomes "above average for what I publish".
Limits and gotchas
- Daily cap: 15 TikTok posts per connected account per rolling 24 h (upload limits).
- Free plan: TikTok uploads return
403; you need a paid plan (pricing & limits). - Rate limits: TikTok allows 6 posts per minute and 15 posts per day per connected TikTok account.
reached_active_user_caperror: a temporary TikTok platform limit. Reconnect the TikTok account to move it to our current publishing route, which is not affected, or apply the inbox workaround.- Video privacy:
privacy_levelworks on video and photo posts alike, but TikTok decides per account which levels are available — a private account has noPUBLIC_TO_EVERYONE. Asking for one the account does not have fails withtiktok_privacy_unavailableand an error listing the ones it does have; omit the field on video and TikTok keeps the account's own default. - Failure codes to branch on: TikTok accepts the job and reports the outcome
afterwards, so a failure arrives on Upload Status,
not on the upload call.
tiktok_media_rejectedmeans TikTok refused the file itself (format, duration, frame rate, resolution or size) — fix the media, a retry of the same file will fail again.tiktok_publish_failedis everything else, including TikTok-side problems, and is worth retrying. Both refund the 24 h allowance, because nothing was published. - Extra TikTok options: attach a Commercial Music Library track (
tiktok_music_id, see Get TikTok Trending Music), tag a place (tiktok_location_id+tiktok_location_name, see Get TikTok Locations) or set a custom cover (tiktok_cover_image_url). Each of them needs its own capability — checkcapabilitiesfirst. tiktok_reconnect_required: a400on the comment, search or insights endpoints. The connection publishes fine but was never granted that permission; the account owner reconnects and it appears. See Common Errors.- Formats: video MP4/MOV/WebM, up to 4 GB, 3–600 s, at least 360 px on the shortest side, 23–60 fps. Photos JPG/JPEG/WebP, up to 35 images of 20 MB each. See Video Requirements and Photo Requirements.