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)

FieldMeaning
privacyLevelPUBLIC_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 / allowStitchInteraction toggles, off unless true (TikTok guidelines). Duet/stitch apply to videos only; ignored when the creator disabled them
drafttrue 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
mediaTypevideo (default) or photo. Photos: 1–35 JPEG/WebP mediaUrls on a verified URL prefix, photoCoverIndex, optional title (≤90, from content) and description (≤4000)
videoCoverTimestampMsFrame used as the video cover
isAigcLabel the video as AI-generated (alias video_made_with_ai)
commercialContentTypenone | brand_organic (your own brand) | brand_content (paid partnership; cannot be SELF_ONLY)
uploadModePULL_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
tiktokSettingsZernio-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

ErrorMeaning
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_mismatchThe level is not in the creator’s privacyLevels: call creator-info first
url_ownership_unverifiedPULL_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_capDaily posting caps (per creator, and per app for unaudited clients)
scope_not_authorizedThe creator did not grant a scope (video.list for videos/analytics, user.info.stats for followers): reconnect
access_token_invalidToken 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.