GET /v1/creator/stats
Followers now, plus everything a creator published in the last N days and how it performed. One request whatever the paging underneath — the walk follows each platform's cursor until a page reaches past the window, the feed runs out, or a six-page cap stops it.
Read this first
These are views on posts published in the window, not views accrued during it. Platforms only ever report a post's lifetime view count, so an accrued figure would need a daily snapshot of every post to difference against. That is stored history, which TikData deliberately does not keep. The response says so in window.basis.
Request
curl "https://tikdata.io/v1/creator/stats?url=https://www.tiktok.com/@tiktok&days=30" \
-H "Authorization: Bearer thr_live_xxx"
| param | default | notes |
|---|---|---|
url |
required (or handle + platform) |
a profile URL, as for /v1/profile |
days |
30 |
1–365 |
platform |
detected | override, or required with handle |
Response — 200
{
"platform": "tiktok",
"handle": "tiktok",
"url": "https://www.tiktok.com/@tiktok",
"name": "TikTok",
"followers": 95640964,
"window": {
"days": 30,
"since": "2026-08-09T16:01:22.000Z",
"until": "2026-09-08T16:01:22.000Z",
"basis": "posts published in the window (not views accrued during it)",
"dates": "exact"
},
"totals": {
"posts": 14,
"views": 3719724,
"likes": 176298,
"comments": 19685,
"shares": 11436,
"saves": 8190,
"reposts": 0,
"quotes": 0
},
"averages": { "viewsPerPost": 265695, "postsPerWeek": 3.27 },
"topPosts": [
{ "id": "7676134473112489247",
"url": "https://www.tiktok.com/@tiktok/video/7676134473112489247",
"created_at": "2026-08-20T15:22:21Z",
"views": 573105, "likes": 30110, "comments": 2791, "shares": 1340,
"saves": 1102, "reposts": 0, "quotes": 0 }
],
"coverage": { "pagesFetched": 1, "postsScanned": 20, "truncated": false },
"billedCalls": 2
}
| field | notes |
|---|---|
followers |
from the profile call made first |
window.dates |
"exact" or "approximate" (YouTube — see below) |
totals.* |
summed over in-window posts; per-platform availability follows the /v1/post table (no downloads in feeds) |
averages.postsPerWeek |
posts / days × 7 |
topPosts |
up to 10, by views |
coverage.truncated |
true means the six-page cap was hit before reaching the window edge — the totals are a floor, not a total; a note explains |
billedCalls |
profile + feed pages (+1 to resolve a YouTube @handle) |
Verified live
| window | followers | posts | views | calls | |
|---|---|---|---|---|---|
| TikTok @tiktok | 30d | 95.6M | 14 | 3,719,724 | 2 |
| Instagram @instagram | 30d | 686.5M | 9 | 898,664,129 | 3 |
| X @nasa | 7d | 92.4M | 8 | 4,628,396 | 2 |
| YouTube @MrBeast | 90d | 516M | 6 | 504,000,000 | 3 |
Per-platform notes
- TikTok pages on
max_cursor.has_morelies, so the dates decide when to stop. - Instagram uses
fetch_user_posts, notfetch_user_reels— only the former returnsnext_max_id/more_available, and it covers reels as well as grid posts. Items come back out of order with pinned posts floated to the top, so a single old item does not end the walk; only a page with nothing in the window does. The list payload carries no share/save/repost counts, so those totals are0for Instagram here even though/v1/posthas them. - YouTube — the channel listing gives relative dates (
"2 months ago"), not timestamps, sowindow.datesis"approximate": days and weeks are precise enough for a 30-day question, months are not. The listing carries no per-post likes or comments. Withoutlanguage_code=enthe payload is Chinese-localised (7.3万次观看) — handled. - X uses
fetch_user_media, which is the right list anyway since clips are media posts.
Cost bound
At most 6 feed pages (+1 profile, +1 YouTube resolve) per request. Page sizes observed live: TikTok 20, Instagram 12, YouTube 30, X ~19. For a creator posting more than ~120 times in the window on TikTok, expect truncated: true.
Errors
| status | body |
|---|---|
| 400 | {"error":"url is required","hint":"GET /v1/creator/stats?url=https://www.tiktok.com/@tiktok&days=30"} |
| 400 | {"error":"days must be between 1 and 365"} |
| 400 | {"error":"unknown platform", …} / {"error":"unrecognized url", …} / {"error":"could not extract a … handle from that url"} |
| 404 | {"error":"profile not found","platform":"…","handle":"…"} |
| 502 | {"error":"feed unavailable","platform":"…","handle":"…","followers":N,"upstreamStatus":400,"hint":"…"} — the profile resolved but the post list could not be read after one retry. This is a 502 on purpose: returning 200 with zero posts for a creator who posts daily would be the false-zero this whole API exists to prevent. |
| 502 | {"error":"upstream unreachable"} / {"error":"could not resolve a … feed id for @…"} |
Retries
Two upstream flakes get exactly one retry each, on any feed page: Instagram's 200-with-"This account does not exist." for accounts that exist, and the provider's 400 whose body literally says "Please retry". A retried 200 is still billed upstream and shows in billedCalls. Nothing else retries.