POST /v1/posts
The batch form of /v1/post. Up to 500 URLs per request, platforms mixed freely, fanned out server-side at the router's own concurrency and rate limit. One slow or dead post never blocks the rest.
Request
curl -X POST "https://tikdata.io/v1/posts" \
-H "Authorization: Bearer thr_live_xxx" \
-H "content-type: application/json" \
-d '{"urls":[
"https://www.tiktok.com/@tiktok/video/7680721699171601694",
"https://x.com/nasa/status/2095890073031966734",
"https://www.instagram.com/reel/Dc30nJeRKKz/",
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
]}'
| field | required | notes |
|---|---|---|
urls |
yes | array of 1–500 post URLs; non-string or empty entries are dropped before counting |
Response — 200
{
"requested": 4,
"succeeded": 3,
"failed": 1,
"results": [
{ "url": "https://www.tiktok.com/@tiktok/video/7680721699171601694",
"ok": true,
"post": { "platform": "tiktok", "id": "7680721699171601694", "…": "same shape as /v1/post" } },
{ "url": "https://www.tiktok.com/@tiktok/video/9999999999999999999",
"ok": false,
"error": "post not found" }
]
}
results is in the same order as urls. Each entry is one of:
| shape | when |
|---|---|
{ url, ok: true, post } |
post is exactly the /v1/post response |
{ url, ok: false, error } |
error is one of the strings below |
| error | meaning |
|---|---|
unrecognized url |
not a TikTok/Instagram/YouTube/X URL |
post not found |
well-formed, but the platform returned no post |
upstream 4xx / upstream 5xx |
the provider returned that status |
upstream unreachable |
timeout or network failure |
Limits and pacing
| max URLs | 500 — more returns 400 {"error":"too many urls","hint":"max 500 per request, got 501"} |
| concurrency | 25 in flight (deployment setting TIKHUB_CONCURRENCY) |
| rate | held under the plan's 100 req/s by a sliding window |
| timeout | 300 s for the whole request; at 500 URLs expect roughly 20–40 s |
Billing
One upstream call per URL that reached the provider, attributed to your key's project. Dead posts are still billed (the provider charges for the 200-with-nothing response). Malformed URLs that never reach the provider cost nothing.
There is no bulk discount underneath: the provider has no working multi-post endpoint, so 500 URLs is 500 billable calls. What you save is 500 round-trips, client-side pacing and per-item error handling.
Errors
| status | body |
|---|---|
| 400 | {"error":"body must be JSON","hint":"{\"urls\":[\"https://...\",\"https://...\"]}"} |
| 400 | {"error":"urls[] is required"} |
| 400 | {"error":"too many urls","hint":"max 500 per request, got N"} |
| 401 | see authentication |
See also
POST /v1/videos/bulk_stats — the same fan-out, but takes {platform, id} pairs and returns one flat row per video with typed error codes.