Posts

Publish to TikTok

Publish a TikTok video, photo, or carousel.

POSThttps://app.tryadeli.com/api/v1/posts
AuthorizationBearer <API key>How keys work

TikTok publishing is asynchronous. A successful request means TikTok accepted the content, not that it is live. Adeli publishes through TikTok API for Business, which pulls every video and photo from a URL: whatever you send — base64, multipart, or a URL — Adeli stages it on its own verified media host first.

Videos are public or drafts

TikTok for Business has no privacy setting for videos. A DIRECT_POST video is published to everyone, so its privacy_level must be PUBLIC_TO_EVERYONE or left out; anything else is 422 privacy_level_unsupported rather than a post that is more public than you asked for. To keep a video private, send post_mode: "MEDIA_UPLOAD": it arrives as a draft in the creator's TikTok inbox. Photo posts accept every privacy_level the creator currently allows.

TikTok allows 15 API posts per account per day.

Before a Direct Post, check creator capabilities first.

Body

platform"tiktok"Required
accountIduuidRequired
A connected TikTok account.
profileIduuid
Optional, because accountId names its profile. If you pass both, they must agree.
post_mode"DIRECT_POST" | "MEDIA_UPLOAD"
Defaults to DIRECT_POST, which publishes. MEDIA_UPLOAD sends a draft to the creator's TikTok inbox to finish in the app; a video draft carries the media only, a photo draft its title and description too.
tiktok_titlestring
Up to 2,200 characters for a video, and up to 90 for photos.
tiktok_descriptionstring
Up to 4,000 characters. Photo posts only.
privacy_levelstring
Videos: PUBLIC_TO_EVERYONE or omitted. Photos: one of PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY that the creator currently allows; defaults to PUBLIC_TO_EVERYONE.
music_usage_confirmedtrueRequired
Must be literally true. You are confirming the creator agreed to TikTok's music usage terms.
disable_commentboolean
Defaults to false.
disable_duetboolean
Video only. Defaults to false.
disable_stitchboolean
Video only. Defaults to false.
cover_timestampinteger
Video only. Milliseconds into the video to use as the cover. Defaults to 1000.
photo_cover_indexinteger
Photos only. Defaults to 0, and must be less than the number of photos.
auto_add_musicboolean
Photos only. Defaults to false.
is_aigcboolean
Marks the content as AI-generated. Defaults to false.
brand_content_toggleboolean
Paid partnership. Requires privacy_level: \"PUBLIC_TO_EVERYONE\" on a Direct Post.
brand_organic_toggleboolean
Promotes the creator's own brand.
videoobject
Either { content_type: "video/mp4", base64 } or { url } pointing at public HTTPS. Mutually exclusive with photos.
photosobject[]
1 to 35 photos, each { content_type, base64 }. Remote photo URLs are not accepted. Mutually exclusive with video.

Exactly one of video or photos

Sending both, or neither, is 400 invalid_request.

The request example sends a video from a public URL to the creator's inbox. A video published publicly:

json
{
  "platform": "tiktok",
  "accountId": "00000000-0000-0000-0000-000000000000",
  "tiktok_title": "Morning chorus #birds",
  "privacy_level": "PUBLIC_TO_EVERYONE",
  "disable_duet": false,
  "disable_stitch": true,
  "music_usage_confirmed": true,
  "video": { "url": "https://media.example/video.mp4" }
}

A photo carousel posted directly, visible only to the creator:

json
{
  "platform": "tiktok",
  "accountId": "00000000-0000-0000-0000-000000000000",
  "post_mode": "DIRECT_POST",
  "tiktok_title": "Backyard birds",
  "tiktok_description": "Cardinal, Titmouse, and Robin",
  "privacy_level": "SELF_ONLY",
  "photo_cover_index": 0,
  "auto_add_music": false,
  "music_usage_confirmed": true,
  "photos": [
    { "content_type": "image/webp", "base64": "..." },
    { "content_type": "image/jpeg", "base64": "..." }
  ]
}

Multipart uploads

For large videos, send multipart/form-data instead. Scalar fields use the same names, booleans must be the strings "true" or "false", and the media is either one video file or 1–35 repeated photos[] files. Multipart is TikTok only.

bash
curl --fail-with-body -X POST "https://app.tryadeli.com/api/v1/posts" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -F 'platform=tiktok' \
  -F "accountId=$ACCOUNT_ID" \
  -F 'post_mode=DIRECT_POST' \
  -F 'privacy_level=PUBLIC_TO_EVERYONE' \
  -F 'tiktok_title=Morning chorus' \
  -F 'music_usage_confirmed=true' \
  -F 'video=@video.mp4;type=video/mp4'
bash
curl --fail-with-body -X POST "https://app.tryadeli.com/api/v1/posts" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -F 'platform=tiktok' \
  -F "accountId=$ACCOUNT_ID" \
  -F 'post_mode=MEDIA_UPLOAD' \
  -F 'music_usage_confirmed=true' \
  -F 'photos[]=@cardinal.webp;type=image/webp' \
  -F 'photos[]=@robin.jpg;type=image/jpeg'

The response

Success returns 202 with a publishId. Pass it to TikTok publish status to learn whether the post went live.

statusUrl is a relative path

Join it to your base URL before requesting it. warnings is present only when non-empty — inbox uploads report the settings TikTok ignored, since a video sent to the inbox carries media and nothing else.