API documentation
Two endpoints: free post metadata, and a full analysis with comments paid from your pack.
Create a tokenAuthorisation
Send the token in the Authorization: Bearer sk_live_… header. Do not put it in the URL — it would end up in server logs and browser history.
Tokens are created in the workspace after the email is confirmed, up to 5 active per account. The full value is shown once — keep it on your server only and revoke it if it leaks. Every token can reach both metadata and analysis; an analysis request spends comments from the balance (otherwise 402 quota_exceeded).
Sandbox — no token needed
POST /api/v1/sandbox/metadata and POST /api/v1/sandbox/analyze return fixtures shaped exactly like the live endpoints: no TikTok, no quota, no token. The IP limit is 5 requests per minute and 30 per hour.
# metadata fixture (no token)
curl -X POST https://api.example.com/api/v1/sandbox/metadata \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@user/video/7300000000000000000"}'
# full analysis fixture (status: complete right away)
curl -X POST https://api.example.com/api/v1/sandbox/analyze \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@user/video/7300000000000000000"}'POST /api/v1/metadata — free
A synchronous response: author, metrics, hashtags, sound, cover and description keywords. No comments here. The limit is 10 requests per 2 hours per account; responses are cached for 5 minutes by URL, and a cache hit ("cached": true) does not spend the limit.
curl -X POST https://api.example.com/api/v1/metadata \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@user/video/7300000000000000000"}'POST /api/v1/analyze — paid from the comment balance
Asynchronous: returns a job_id with status queued, and the result is fetched with GET /api/v1/analyze/{job_id}. Poll once every 1–2 seconds; statuses are queued, in_progress, complete and failed. Someone else's job returns 404. In comments, replies are already nested inside their parent as replies.
# create a job
curl -X POST https://api.example.com/api/v1/analyze \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@user/video/7300000000000000000"}'
# response: {"job_id": "b1e2...", "status": "queued"}
# fetch the result
curl https://api.example.com/api/v1/analyze/b1e2... \
-H "Authorization: Bearer sk_live_..."Repeating the same URL
The same URL is never parsed twice. If a job is still running you get its job_id back ("deduplicated": "in_flight"). If a result arrived less than 5 minutes ago, the finished job is returned ("deduplicated": "recent_result"). Neither case spends quota.
Idempotency-Key
Optional. If you send an Idempotency-Key header with a unique value, a repeat with the same key within 24 hours returns the same job_id instead of a new job. Ordinary requests do not need this header.
Limits and quotas
| Limit | Value |
|---|---|
| Metadata | 10 requests / 2 hours |
| Comments | by purchased packs (balance for the calendar month) |
| Comments per post | up to 5,000 |
| Concurrent analyses | 3 |
Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, X-Quota-Limit and X-Quota-Remaining, plus Retry-After in seconds on a 429. The current state is also available from GET /api/v1/usage.
When the comment balance runs out, analysis answers 402 quota_exceeded: buy a pack on the comments page and it is added to the current month.
Errors
Error body: {"detail": "...", "code": "machine_code"}
| HTTP | code | When |
|---|---|---|
| 401 | unauthorized | The token is missing, revoked or invalid |
| 403 | forbidden_scope | The token lacks the required scope |
| 402 | quota_exceeded | No comments available — buy a pack |
| 429 | rate_limited | Request limit exceeded, see the Retry-After header |
| 429 | concurrency_limit | Three analyses are already running at once |
| 400 | validation_error | Invalid URL or unsupported platform |
| 502 | parse_error | Could not fetch the post data |
| 404 | not_found | The job does not exist or belongs to another user |