# TikTok API for agents

> API for Agents · https://apiforagents.dev/platforms/tiktok · HTML twin: https://apiforagents.dev/platforms/tiktok

Creators, videos, comments, followers, search and shop listings from TikTok.

Endpoint: `POST https://apiforagents.dev/v1/tiktok`. One op per call. Quote first with `"estimateOnly": true`.

## Prices (USD per record, pay as you go)

| Record | Per record |
|---|---|
| comments | $0.00045 |
| followers | $0.0009 |
| posts | $0.0018 |
| profiles | $0.0022 |
| shop | $0.013 |

## Operations

### profiles

Profile cards for up to ten accounts by @handle or profile URL. Followers, following, total likes, video count, bio, verification.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | @handles or profile URLs. |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| handle | string |
| tiktokId | string |
| displayName | string |
| profileUrl | string |
| avatar | string |
| bio | string |
| bioLink | string |
| verified | boolean |
| private | boolean |
| businessAccount | boolean |
| businessCategory | string |
| tiktokSeller | boolean |
| followers | integer |
| following | integer |
| totalLikes | integer |
| likesGiven | integer |
| videos | integer |
| mutualFollows | integer |
| accountCreated | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"profiles","subjects":["@nba","@natgeo"]}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "handle": "@mira.moves",
    "displayName": "Mira | Pilates",
    "bio": "New class every Monday 🧘",
    "verified": true,
    "businessAccount": true,
    "businessCategory": "Fitness",
    "followers": 1240000,
    "following": 312,
    "totalLikes": 41200000,
    "videos": 642,
    "tiktokId": "2692099489",
    "profileUrl": "https://www.tiktok.com/mira-pilates-1000",
    "bioLink": "https://www.tiktok.com/mira-pilates-1000",
    "accountCreated": "2026-10-07",
    "details": {}
  },
  {
    "handle": "@cookwithkai",
    "displayName": "Cook with Kai",
    "bio": "Dinner in 30 minutes or less",
    "verified": true,
    "businessAccount": false,
    "businessCategory": null,
    "followers": 860000,
    "following": 190,
    "totalLikes": 22100000,
    "videos": 418,
    "tiktokId": "3614854177",
    "profileUrl": "https://www.tiktok.com/cook-with-kai-1001",
    "bioLink": "https://www.tiktok.com/cook-with-kai-1001",
    "accountCreated": "2026-10-01",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=profiles (sign in first).

### posts

One account's recent posts. Views, likes, comments, shares, saves, sound, hashtags, duration; includes the author card when held.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subject | yes | string (≤400 chars) | One @handle or profile URL. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| postId | string |
| postUrl | string |
| authorHandle | string |
| caption | string |
| postedDate | string |
| views | integer |
| likes | integer |
| comments | integer |
| shares | integer |
| saves | integer |
| durationS | integer |
| language | string |
| isSlideshow | boolean |
| isSponsored | boolean |
| isAd | boolean |
| hashtags | list of string |
| mentions | list of string |
| sound | any |
| location | string |
| locationAddress | string |
| country | string |
| thumbnail | string |
| resolution | string |
| effects | list of string |
| slideshowImages | any |
| hashtagViews | integer |
| sourceQuery | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"posts","subject":"@nba","limit":20}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "authorHandle": "@mira.moves",
    "caption": "60-second core burner #pilates",
    "postedDate": "2026-10-14",
    "views": 2410000,
    "likes": 312000,
    "comments": 2100,
    "shares": 14200,
    "saves": 88000,
    "durationS": 60,
    "hashtags": [
      "pilates",
      "core"
    ],
    "postId": "18940392",
    "postUrl": "https://www.tiktok.com/60-second-core-burner-pilates-1000",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  },
  {
    "authorHandle": "@mira.moves",
    "caption": "Pilates for back pain, gentle version",
    "postedDate": "2026-10-11",
    "views": 980000,
    "likes": 104000,
    "comments": 1320,
    "shares": 9100,
    "saves": 61000,
    "durationS": 74,
    "hashtags": [
      "pilates",
      "backpain"
    ],
    "postId": "835950238",
    "postUrl": "https://www.tiktok.com/pilates-for-back-pain-gentle-version-1001",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=posts (sign in first).

### videos

Full cards for up to ten posts by video or photo URL.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Video or photo URLs. |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| postId | string |
| postUrl | string |
| authorHandle | string |
| caption | string |
| postedDate | string |
| views | integer |
| likes | integer |
| comments | integer |
| shares | integer |
| saves | integer |
| durationS | integer |
| language | string |
| isSlideshow | boolean |
| isSponsored | boolean |
| isAd | boolean |
| hashtags | list of string |
| mentions | list of string |
| sound | any |
| location | string |
| locationAddress | string |
| country | string |
| thumbnail | string |
| resolution | string |
| effects | list of string |
| slideshowImages | any |
| hashtagViews | integer |
| sourceQuery | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"videos","subjects":["https://www.tiktok.com/@nba/video/<video-id>"]}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "authorHandle": "@cookwithkai",
    "caption": "Crispy rice in 5 minutes",
    "postedDate": "2026-10-12",
    "views": 1180000,
    "likes": 140000,
    "comments": 980,
    "shares": 8600,
    "saves": 52000,
    "durationS": 35,
    "hashtags": [
      "easyrecipes"
    ],
    "postId": "2158438716",
    "postUrl": "https://www.tiktok.com/crispy-rice-in-5-minutes-1000",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  },
  {
    "authorHandle": "@cookwithkai",
    "caption": "One-pan laksa",
    "postedDate": "2026-10-09",
    "views": 640000,
    "likes": 71000,
    "comments": 520,
    "shares": 4100,
    "saves": 33000,
    "durationS": 58,
    "hashtags": [
      "laksa"
    ],
    "postId": "55945509",
    "postUrl": "https://www.tiktok.com/one-pan-laksa-1001",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=videos (sign in first).

### searchPosts

Posts by keyword, by hashtag, or by sound URL. Exactly one.

| Field | Required | Type | Meaning |
|---|---|---|---|
| query | no | string (≤300 chars) |  |
| hashtag | no | string (≤150 chars) |  |
| soundUrl | no | string (≤400 chars) | A TikTok sound page URL (tiktok.com/music/…): posts made with that sound. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| postId | string |
| postUrl | string |
| authorHandle | string |
| caption | string |
| postedDate | string |
| views | integer |
| likes | integer |
| comments | integer |
| shares | integer |
| saves | integer |
| durationS | integer |
| language | string |
| isSlideshow | boolean |
| isSponsored | boolean |
| isAd | boolean |
| hashtags | list of string |
| mentions | list of string |
| sound | any |
| location | string |
| locationAddress | string |
| country | string |
| thumbnail | string |
| resolution | string |
| effects | list of string |
| slideshowImages | any |
| hashtagViews | integer |
| sourceQuery | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"searchPosts","hashtag":"booktok","limit":25}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "authorHandle": "@homebarista",
    "caption": "Espresso at home for under $300 #coffee",
    "postedDate": "2026-10-13",
    "views": 3100000,
    "likes": 402000,
    "comments": 5200,
    "shares": 31000,
    "saves": 140000,
    "durationS": 64,
    "hashtags": [
      "coffee",
      "espresso"
    ],
    "postId": "1544575846",
    "postUrl": "https://www.tiktok.com/espresso-at-home-for-under-300-coffee-1000",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  },
  {
    "authorHandle": "@latteart.lou",
    "caption": "Rosetta in slow motion #coffee",
    "postedDate": "2026-10-12",
    "views": 880000,
    "likes": 96000,
    "comments": 1100,
    "shares": 4200,
    "saves": 19000,
    "durationS": 18,
    "hashtags": [
      "coffee",
      "latteart"
    ],
    "postId": "113019651",
    "postUrl": "https://www.tiktok.com/rosetta-in-slow-motion-coffee-1001",
    "isSlideshow": false,
    "isSponsored": false,
    "isAd": false,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=searchPosts (sign in first).

### search

Find accounts by keyword. Every hit a full profile card.

| Field | Required | Type | Meaning |
|---|---|---|---|
| query | yes | string (≤300 chars) |  |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| handle | string |
| tiktokId | string |
| displayName | string |
| profileUrl | string |
| avatar | string |
| bio | string |
| bioLink | string |
| verified | boolean |
| private | boolean |
| businessAccount | boolean |
| businessCategory | string |
| tiktokSeller | boolean |
| followers | integer |
| following | integer |
| totalLikes | integer |
| likesGiven | integer |
| videos | integer |
| mutualFollows | integer |
| accountCreated | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"search","query":"home cooking","limit":10}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "handle": "@latteart.lou",
    "displayName": "Lou | Latte Art",
    "bio": "Pouring hearts daily",
    "verified": false,
    "followers": 312000,
    "following": 140,
    "totalLikes": 8400000,
    "videos": 520,
    "businessAccount": null,
    "tiktokId": "673577550",
    "profileUrl": "https://www.tiktok.com/lou-latte-art-1000",
    "bioLink": "https://www.tiktok.com/lou-latte-art-1000",
    "accountCreated": "2026-10-04",
    "details": {}
  },
  {
    "handle": "@brewlab",
    "displayName": "Brewlab Coffee",
    "bio": "Coffee nerds from Austin",
    "verified": false,
    "followers": 52100,
    "following": 88,
    "totalLikes": 610000,
    "videos": 214,
    "businessAccount": true,
    "tiktokId": "994794249",
    "profileUrl": "https://www.tiktok.com/brewlab-coffee-1001",
    "bioLink": "https://www.tiktok.com/brewlab-coffee-1001",
    "accountCreated": "2026-10-02",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=search (sign in first).

### comments

Top-level comments on up to ten posts by URL.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Video or photo URLs. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| commentId | string |
| comment | string |
| likes | integer |
| replies | integer |
| postedDate | string |
| commenter | string |
| commenterId | string |
| commenterUrl | string |
| commenterAvatar | string |
| pinnedByCreator | boolean |
| likedByCreator | boolean |
| mentions | list of string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"comments","subjects":["https://www.tiktok.com/@nba/video/<video-id>"],"limit":50}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "commenter": "@ravi.k",
    "comment": "Doing this every morning now",
    "likes": 2140,
    "replies": 12,
    "postedDate": "2026-10-14",
    "pinnedByCreator": false,
    "likedByCreator": true,
    "commentId": "4152526865",
    "commenterId": "1659980969",
    "commenterUrl": "https://www.tiktok.com/ravi-k-1000",
    "details": {}
  },
  {
    "commenter": "@lena_m",
    "comment": "Song name?",
    "likes": 980,
    "replies": 41,
    "postedDate": "2026-10-14",
    "pinnedByCreator": false,
    "likedByCreator": false,
    "commentId": "2242419321",
    "commenterId": "3716159273",
    "commenterUrl": "https://www.tiktok.com/lena-m-1001",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=comments (sign in first).

### followers

The followers OR following of up to five accounts, each row a full profile.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-5 items) | @handles or profile URLs. |
| direction | no | enum |  Values: followers, following. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| handle | string |
| userId | string |
| displayName | string |
| profileUrl | string |
| avatar | string |
| bio | string |
| verified | boolean |
| private | boolean |
| followers | integer |
| following | integer |
| videos | integer |
| totalLikes | integer |
| tiktokSeller | boolean |
| connectionType | string |
| connectedAccount | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"followers","subjects":["@nba"],"direction":"following","limit":50}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "handle": "@ravi.k",
    "displayName": "Ravi",
    "followers": 412,
    "following": 830,
    "videos": 12,
    "connectionType": "follower",
    "userId": "4157080663",
    "profileUrl": "https://www.tiktok.com/ravi-1000",
    "details": {}
  },
  {
    "handle": "@lena_m",
    "displayName": "Lena",
    "followers": 2100,
    "following": 410,
    "videos": 58,
    "connectionType": "follower",
    "userId": "4017953218",
    "profileUrl": "https://www.tiktok.com/lena-1001",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=followers (sign in first).

### shop

TikTok Shop products for a keyword. Price, discount, rating, sold count, seller, every variant with its stock.

| Field | Required | Type | Meaning |
|---|---|---|---|
| query | yes | string (≤300 chars) |  |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| productId | string |
| productUrl | string |
| title | string |
| description | string |
| salePrice | number |
| originalPrice | number |
| discount | string |
| currency | string |
| rating | number |
| reviewCount | integer |
| soldCount | integer |
| seller | any |
| image | string |
| labels | list of string |
| variants | any |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/tiktok \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"shop","query":"resistance bands","limit":20}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "title": "Resistance bands set (5)",
    "seller": "Mira Moves Shop",
    "salePrice": 19.99,
    "originalPrice": 29.99,
    "discount": "33%",
    "currency": "USD",
    "rating": 4.7,
    "reviewCount": 2310,
    "soldCount": 12400,
    "productId": "279510755",
    "productUrl": "https://www.tiktok.com/resistance-bands-set-5-1000",
    "details": {}
  },
  {
    "title": "Non-slip yoga mat",
    "seller": "Mira Moves Shop",
    "salePrice": 34,
    "originalPrice": 45,
    "discount": "24%",
    "currency": "USD",
    "rating": 4.8,
    "reviewCount": 1450,
    "soldCount": 8800,
    "productId": "2036470454",
    "productUrl": "https://www.tiktok.com/non-slip-yoga-mat-1001",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=shop (sign in first).

### history (free)

Stored follower/likes/video-count series of profiles already held. Free.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) |  |
| metric | no | enum |  Values: followers, following, total_likes, videos. |
| days | no | integer (1-730) |  |

Request shape:

```json
{
  "op": "history",
  "subjects": [
    "example"
  ]
}
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=tiktok&op=history (sign in first).

## Notes for the agent

Measured TikTok data, one operation per call. Handles come from evidence (a pasted tiktok.com/@ URL, a handle you SAW, a prior answer). Never typed from a person's name. ops: profiles (cards for up to ten accounts. Followers, following, total likes, video count, bio, verification, business/seller flags), posts (one account's recent posts. Views, likes, comments, shares, saves, sound, hashtags, duration), videos (full cards for up to ten posts by URL), searchPosts (posts by keyword OR hashtag OR sound URL), search (find accounts by keyword), comments (top-level comments on up to ten posts), followers (the followers OR following of up to five accounts, each a full profile), shop (TikTok Shop products for a keyword. Price, discount, rating, sold count, seller, variants with stock), history (stored follower/likes/video series, free). Ops are independent. Issue several as PARALLEL tool calls. Fresh fetches are charged per record; your own answer is free while fresh.
