<!-- https://cutedyno.com/docs/platforms/tiktok -->

# TikTok

Video and photo posts, privacy levels, commercial disclosure, and the app audit that decides who can see them.

TikTok accepts video and photo posts. It rejects text-only posts, and it is stricter than the other platforms about who is allowed to publish publicly.

## The audit problem

Read this before anything else. TikTok's Content Posting API has two tiers:

- **Unaudited app** — every post is forced to `SELF_ONLY`. Visible to the creator, nobody else. The API accepts the post and returns success.
- **Audited app** — posts can be public.

If your posts publish successfully and no one can see them, this is why, and no amount of debugging your integration will change it. Apply for audit in the TikTok Developer Portal.

A related failure is domain verification: TikTok fetches video from the URL you supply, and refuses URLs on unverified domains with `url_ownership_unverified`. URLs from [`/v1/media/upload`](/docs/api/create-media-upload) are on a verified domain, so use them unless you have verified your own.

## Video

```typescript
await cutedyno.posts.create({
  content: 'Three ways to use the new grinder.',
  media: [{ type: 'video', url: videoUrl }],
  accountIds: [tiktokAccountId],
  platforms: {
    tiktok: {
      title: 'Three ways to use the new grinder',
      privacy_level: 'PUBLIC_TO_EVERYONE',
      disable_duet: true,
      video_cover_timestamp_ms: 2000,
    },
  },
});
```

Publishing is asynchronous on TikTok's side as well as ours: CuteDyno hands over the URL, TikTok downloads and processes the video, and we poll for up to ten minutes before giving up. A post can sit in `processing` for several minutes for a large video, which is normal.

`content` becomes the caption. `platforms.tiktok.title` is the video's title, which TikTok treats separately.

## Photos

```typescript
await cutedyno.posts.create({
  content: 'Roastery, 6am.',
  media: [
    { type: 'image', url: firstUrl },
    { type: 'image', url: secondUrl },
  ],
  accountIds: [tiktokAccountId],
  platforms: { tiktok: { title: 'Roastery, 6am' } },
});
```

Photo titles are capped at 90 characters and trimmed for you, taking the first line or sentence of your caption when you do not supply a title. The caption goes through in full as the description.

Images must be JPEG or WebP. Anything else — PNG, GIF — is converted to JPEG before upload, so you do not have to think about it.

## Duration

TikTok's maximum video length depends on the creator's account, not on your app. CuteDyno reads that limit per account and rejects a longer video before uploading, with the account's actual maximum in the message. There is no fixed number to code against.

## Options

| Option | Effect |
| --- | --- |
| `title` | Video title, or photo title. Distinct from the caption. |
| `privacy_level` | `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, `SELF_ONLY`. Defaults to the widest the creator allows. |
| `disable_comment` | Turn off comments. |
| `disable_duet` | Turn off duets. |
| `disable_stitch` | Turn off stitches. |
| `video_cover_timestamp_ms` | Frame to use as the cover. Defaults to 1 second in. |
| `brand_content_toggle` | Discloses a paid partnership. |
| `brand_organic_toggle` | Discloses the creator promoting their own brand. |
| `is_aigc` | Marks the video as AI-generated. |
| `auto_add_music` | Let TikTok suggest music for photo posts. |
| `upload_as_draft` | Send to the creator's TikTok drafts instead of publishing. |

`privacy_level` is validated against what the creator's account actually permits, so a private account cannot be made to post publicly by passing a wider value.

## Commercial disclosure

If `brand_content_toggle` is set, TikTok requires the disclosure to be coherent: branded content cannot also be `SELF_ONLY`, and you must indicate whether the content promotes the creator, a third party, or both. Incoherent combinations are rejected before upload with a message naming the problem.

## Drafts

`upload_as_draft: true` sends the video to the creator's TikTok inbox instead of publishing. They finish and post it from the app.

This is the honest option for an unaudited app: rather than publishing something only the creator can see, put it in their drafts where they expect to find it. TikTok allows five pending inbox drafts per 24 hours.

## Failures worth handling

| Message | Meaning |
| --- | --- |
| `unaudited_client_can_only_post_to_private_accounts` | Your app is not audited. See above. |
| `url_ownership_unverified` | The media URL's domain is not verified with TikTok. |
| `spam_risk_too_many_pending_share` | Too many pending posts. Slow down. |
| This TikTok account cannot post more right now | The creator hit TikTok's own rate limit. Retry later. |
| Video exceeds TikTok max duration | Shorter video needed; the message carries the account's limit. |

These arrive in `results[].error` for the TikTok account. Other accounts in the same post are unaffected.

## Analytics

Per-video views, likes, comments, and shares, plus follower and video counts on the account. TikTok does not expose audience demographics to the API, so those are unavailable rather than empty.

## Comments

Not supported. TikTok has no comment webhook or moderation API for this integration, so TikTok comments do not appear in [`GET /v1/comments`](/docs/api/list-comments).
