TikTok
Postgale publishes to TikTok through the official Login Kit and Content Posting API: videos and photo carousels as direct posts or as drafts in the creator's inbox, with privacy, interaction, cover, AI-label and commercial-content options. It also reads the creator's posting options, profile, videos and metrics (Display API). Everything is on the REST API (paths relative to https://postgale.com/api/v1) and the MCP server (create_post, tiktok_*).
Connect
GET /connect/tiktok (or the dashboard) returns a TikTok authorization URL (TikTok Login Kit, OAuth 2.0). Postgale asks for user.info.basic, user.info.profile, user.info.stats, video.list, video.publish and video.upload; video.publish is required. Access tokens last 24 hours and are refreshed by Postgale with the 365-day refresh token.
Before posting: creator info
TikTok requires apps to show the creator's current options before each post. Read them, then pick a privacy level from privacyLevels where allowedNow is true.
curl https://postgale.com/api/v1/accounts/acc_tiktok/tiktok/creator-info \
-H 'Authorization: Bearer sk_…'Publish a video
curl -X POST https://postgale.com/api/v1/posts \
-H 'Authorization: Bearer sk_…' \
-H 'Content-Type: application/json' \
-d '{"content":"New drop #postgale","publishNow":true,"platforms":[{"accountId":"acc_tiktok","platformSpecificData":{"mediaUrl":"https://media.postgale.com/postgale-media/org/clip.mp4","privacyLevel":"SELF_ONLY","allowComment":true,"isAigc":false}}]}'Publishing is asynchronous: the target stays publishing until the worker sees PUBLISH_COMPLETE from TikTok. Public posts get platformPostId = the TikTok video id and a link; SELF_ONLY posts have no public id.
Photo carousel
curl -X POST https://postgale.com/api/v1/posts \
-H 'Authorization: Bearer sk_…' \
-H 'Content-Type: application/json' \
-d '{"content":"Trip highlights","publishNow":true,"platforms":[{"accountId":"acc_tiktok","platformSpecificData":{"mediaType":"photo","mediaUrls":["https://media.postgale.com/…/1.jpg","https://media.postgale.com/…/2.jpg"],"photoCoverIndex":0,"description":"Day one","privacyLevel":"SELF_ONLY"}}]}'Draft to the TikTok inbox
curl -X POST https://postgale.com/api/v1/posts \
-H 'Authorization: Bearer sk_…' \
-H 'Content-Type: application/json' \
-d '{"content":"For review","publishNow":true,"platforms":[{"accountId":"acc_tiktok","platformSpecificData":{"mediaUrl":"https://media.postgale.com/…/clip.mp4","draft":true}}]}'The target becomes published once TikTok delivers the draft (status SEND_TO_USER_INBOX); the creator finishes it in the app. TikTok allows about 5 pending drafts per creator per 24 hours.
Options (platformSpecificData)
| Field | Meaning |
|---|---|
privacyLevel | PUBLIC_TO_EVERYONE | MUTUAL_FOLLOW_FRIENDS | FOLLOWER_OF_CREATOR | SELF_ONLY. Required for direct posts, no default; must be one of the creator’s privacyLevels. Until the app is audited only SELF_ONLY works |
allowComment / allowDuet / allowStitch | Interaction toggles, off unless true (TikTok guidelines). Duet/stitch apply to videos only; ignored when the creator disabled them |
draft | true sends the media to the creator’s TikTok inbox (upload mode, scope video.upload): they finish and post it in the app. No privacy needed |
mediaType | video (default) or photo. Photos: 1–35 JPEG/WebP mediaUrls on a verified URL prefix, photoCoverIndex, optional title (≤90, from content) and description (≤4000) |
videoCoverTimestampMs | Frame used as the video cover |
isAigc | Label the video as AI-generated (alias video_made_with_ai) |
commercialContentType | none | brand_organic (your own brand) | brand_content (paid partnership; cannot be SELF_ONLY) |
uploadMode | PULL_FROM_URL (TikTok downloads mediaUrl; prefix must be verified) or FILE_UPLOAD (Postgale streams the file in 5–64 MB chunks). Default: PULL_FROM_URL for verified prefixes, FILE_UPLOAD otherwise |
tiktokSettings | Zernio-compatible object: privacy_level, allow_comment, allow_duet, allow_stitch, draft, media_type, photo_cover_index, description, video_cover_timestamp_ms, video_made_with_ai, commercialContentType, brandPartnerPromote, isBrandOrganicPost |
Limits: video caption 2,200 characters, photo title 90, description 4,000, 35 photos, videos up to 4 GB and the creator's maxVideoDurationSec.
Profile, videos and analytics
curl https://postgale.com/api/v1/accounts/acc_tiktok/tiktok/profile \
-H 'Authorization: Bearer sk_…'
curl https://postgale.com/api/v1/accounts/acc_tiktok/tiktok/videos?limit=20 \
-H 'Authorization: Bearer sk_…'
curl https://postgale.com/api/v1/analytics/accounts/acc_tiktok \
-H 'Authorization: Bearer sk_…'
curl https://postgale.com/api/v1/analytics/posts/post_123 \
-H 'Authorization: Bearer sk_…'Account analytics return follower_count, following_count, likes_count, video_count and views/likes/comments/shares summed over the latest 20 videos. Post analytics read views, likes, comments and shares of public videos. Pass videoIds (comma-separated) to the videos endpoint to read specific videos.
Errors
| Error | Meaning |
|---|---|
TikTok app is unaudited: only SELF_ONLY… | A non-private privacyLevel before TikTok approved the app (Postgale checks first; TikTok answers unaudited_client_can_only_post_to_private_accounts) |
privacy_level_option_mismatch | The level is not in the creator’s privacyLevels: call creator-info first |
url_ownership_unverified | PULL_FROM_URL from a domain/prefix that is not verified for the app: verify it or use uploadMode FILE_UPLOAD |
spam_risk_too_many_posts / reached_active_user_cap | Daily posting caps (per creator, and per app for unaudited clients) |
scope_not_authorized | The creator did not grant a scope (video.list for videos/analytics, user.info.stats for followers): reconnect |
access_token_invalid | Token expired or revoked: Postgale refreshes automatically; if the refresh token is gone the account is marked reconnect_required |
Not available through TikTok's public APIs (Business API only): location tags, commercial music library, comments and DMs.