URL: /code/integrations/tiktok · Id: `page:/code/integrations/tiktok`

# TikTok

> Your agents send each clip to your TikTok with its caption, post it publicly as you, and read which clips earn views worth promoting.

Your agents send each clip to your TikTok with its caption, post it publicly as you, and read which clips earn views worth promoting.

```text title="Run it · Ask"
Send my late-rent clip to my TikTok with its caption for Thursday, and show me how it will post.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Post.schedule({ handle: 'tiktok:leaseline', format: 'shortVideo', file: 'files/clip-late-rent', body: '3 texts that end late rent #propertymanagement #landlord', at: '2026-10-29T23:00:00Z' })
```

```json title="Run it · Response"
{
  "$type": "Post",
  "mode": "try",
  "stored": false,
  "venue": "tiktok",
  "status": "scheduled",
  "at": "2026-10-29T23:00:00Z",
  "captionLength": 56,
  "steps": [
    "sent to your TikTok inbox by API",
    "posted publicly by the browser agent, signed in as you"
  ],
  "inboxWaiting": 1
}
```

- **Connect:** Sign in once, 4 grants
- **Runs through:** [Your account or a browser agent](/code/integrations#three-ways)
- **First run:** See what is trending in your category, about 0.1¢
- **Sites:** [TikTok](/venues#tiktok)

## Connect once
1. Call `Integration.connect` with `system: 'social'` and `venue: 'tiktok'`, then open the `connectUrl` it returns and sign in as the TikTok account you post from.
2. Sign in once more in the browser window the platform opens; that saved session presses Post on the clips your agents send.
3. Call `Handle.connect` to bind the account as your account.

| Grant | What it unlocks | Scope |
| --- | --- | --- |
| Your profile and its numbers | Your handle, follower count and likes, for the readout | `user.info.basic user.info.stats` |
| Your videos | Each clip’s views, likes, comments and shares | `video.list` |
| Upload | Clips sent to your TikTok inbox with their caption, ready to post | `video.upload` |
| Your saved session | The Post button on each clip, pressed as you | `browser session: tiktok.com` |

| To | Do this |
| --- | --- |
| Pause | `Integration.pause` stops every call through TikTok at once and keeps the token; `Integration.resume` picks up from the same cursor. |
| Reconnect | `Integration.reconnect` returns a fresh `connectUrl` that lasts one hour, and keeps the Integration's id and cursor, so nothing imports twice. |
| Disconnect | `Integration.revoke` revokes the token with TikTok; every record it brought in stays in your records. |

## What your agents do
| Ask | Verb | Runs through | Price |
| --- | --- | --- | --- |
| Send this clip to my TikTok with the caption, ready for Thursday. | [`Post.schedule`](/code/apps/social/schedule) | Your account | Free |
| Post it publicly on Thursday at 18:00, signed in as me. | [`Post.publish`](/code/apps/social/publish) | A browser agent | About 1.6¢ a step |
| Which of my clips beat my median views this month? | [`Metric.query`](/code/apps/analytics-and-experiments/query) | Your account | Free |

Calls on your own account are free.

Reading this site’s public data needs no account: [`Keyword.find`](/code/data/keywords/find), [`Keyword.search`](/code/data/keywords/search) are Data calls (the [three ways a call runs](/code/integrations#three-ways)).

## What it holds
| Noun | The account’s object | When | Which side leads |
| --- | --- | --- | --- |
| [Post](https://startupbuilder.dev/business/nouns/post) | `video` | Your agent sends a clip, then posts it | Your records |
| [Message](https://startupbuilder.dev/business/nouns/message) | `comment` | Someone comments on a clip | The account |

## Events and webhooks
| Direction | Event |
| --- | --- |
| Emits | `Post.scheduled`, `Post.published`, `Message.created` |
| Hears `post.publish.publicly_available` | Becomes `Post.published` |

Any Event can wake a Workflow, and a Watch delivers it to your endpoint, signed ([Events and webhooks](/code/events)).

## Limits
| What | Limit | Call |
| --- | --- | --- |
| Public posts | Each clip reaches your TikTok inbox by API, and the browser agent presses Post as you, so it goes public on your account | [`Post.publish`](/code/apps/social/publish) |
| Clips waiting in your inbox | At most 5 in any 24 hours; a sixth waits with `quota-reached` until one is posted | [`Post.schedule`](/code/apps/social/schedule) |
| Upload calls | 6 a minute for your account; the platform queues the rest | [`Post.schedule`](/code/apps/social/schedule) |
| Posts a day | TikTok caps posts a day per creator; past it a post refuses with `quota-reached` and runs the next day | [`Post.publish`](/code/apps/social/publish) |

## Start here
| Move | The rule |
| --- | --- |
| Structure | One account posting 3 clips a week in one repeatable format: the problem in the first 2 seconds, the fix on screen, the result last. |
| Budget | No spend until a clip earns 3 times your median views; that clip becomes a Spark Ad in TikTok Ads. |
| Creative | Vertical, captions burned in, one problem per clip in the words property managers use; hashtags from this week’s trending list, not from memory. |
| Kill rule | If 9 clips in one format stay under your median, change the opening, not the topic; drop the format after 2 rewrites. |

| Benchmark | Source |
| --- | --- |
| At most 5 clips waiting in your inbox in any 24 hours | TikTok Content Posting API |
| Judge a format at 9 clips | Our planning number |
| Promote a clip only at 3 times your median views | Our planning number |

## Field map
| Our field | TikTok’s field | Notes | Calls |
| --- | --- | --- | --- |
| `Post.body` | `post_info.title` | The caption: 2,200 characters, hashtags included | [`Post.schedule`](/code/apps/social/schedule), [`Post.publish`](/code/apps/social/publish) |
| `Post.media` | `source_info.source` | FILE_UPLOAD or PULL_FROM_URL | [`Post.schedule`](/code/apps/social/schedule) |
| `Post.status` | `privacy_level` | One of the options your account reports; PUBLIC_TO_EVERYONE when the browser agent posts | [`Post.publish`](/code/apps/social/publish) |

## What try does here
Checks the clip and caption against what your account reports it allows, and returns the post as it will show; nothing reaches your inbox.

## How long a connection lasts
A connection lasts 365 days from your first sign-in, the life of TikTok’s refresh token; the platform renews the 24-hour access token on its own.

The platform asks you to reconnect 7 days before it runs out; until you do, a call that needs it refuses with [`needs-reauth`](/code/refusals#needs-reauth).

## Formats
| Site | Format | Size | Limits |
| --- | --- | --- | --- |
| [TikTok](/venues#tiktok) | Video | None. | Caption 2,200 characters, hashtags included; length up to what your account reports |
| [TikTok](/venues#tiktok) | Spark Ad | None. | A post already on your account, promoted with its likes and comments kept |

## Plays and strategies
| Kind | Where |
| --- | --- |
| Plays | [Video ladder](/plays/video-ladder), [Organic social](/plays/organic-social), [Test with a creator](/plays/creator-probe), [Creator partnership](/plays/creator-partnership) |
| Strategies | [Launch and search](/strategy/launch-and-search) |

## Used by
No Workflow, agent task or Service acts through it yet: your agents call it directly.

## Reference

| Call | Path | Price |
| --- | --- | --- |
| [`Post.schedule`](/code/apps/social/schedule) | `POST /posts/schedule` | Free |
| [`Post.publish`](/code/apps/social/publish) | `POST /posts/publish` | About 1.6¢ a step |
| [`Metric.query`](/code/apps/analytics-and-experiments/query) | `POST /metrics/query` | Free |