API documentation

The Bearer token from the cabinet uses the same account data: library, watch, AI and keywords, plus metadata and comment collection.

Create a token

Authorisation

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. The same token as the cabinet covers the scopes below: metadata:read, analyze:write, library:write, ai:write, keywords:write. Send the token only in the Authorization header. An analysis request spends comments from the balance (otherwise 402 quota_exceeded). CORS: Bearer works from any origin without cookies; a cookie session is limited to our domains and needs CSRF.

ScopeAccess
metadata:readFree post metadata
analyze:writeComment collection jobs
library:writeSaved posts, watch, refresh
ai:writeQuote, run, watch phrases
keywords:writeKeywords, channels, alerts

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. With a token or session the limit is 10 requests per 2 hours per account. From the website without signing in: 10 requests per day (browser only). A failed lookup does not spend the limit. Responses are cached for 5 minutes by URL, and a cache hit ("cached": true) does not spend the limit. Curl and your own clients need a Bearer token.

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. A saved breakdown and comment media files last 14 days from the last full comment scrape; opening a bookmark does not extend that.

# 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.

Library and watch

POST /api/v1/analyses/{ref}/save bookmarks a post. List with GET /api/v1/analyses/saved, load GET /api/v1/analyses/{ref}, remove with DELETE /api/v1/analyses/{ref}. Turn on auto-refresh with PUT /api/v1/analyses/{ref}/watch and run a full scrape with POST /api/v1/analyses/{ref}/refresh. The latest browser session is GET /api/v1/analyses/session.

A token analyze auto-saves with bookmark_if_absent: the post is already in the library when the job completes. Polling GET /api/v1/analyze/{job_id} does not extend the 14-day TTL.

From analyze to the library

With a token the finished job is already bookmarked. Then you can watch the post or run AI — the same analysis_id is the ref.

# 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"}'

# fetch the result
curl https://api.example.com/api/v1/analyze/b1e2... \
  -H "Authorization: Bearer sk_live_..."
# complete job — analysis_id is already in the library: {"status":"complete","result":{"analysis_id":"tiktok:7300..."}}

# optional: auto-refresh
curl -X PUT https://api.example.com/api/v1/analyses/tiktok:7300.../watch \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"enabled": true, "interval_min": 60}'

# optional: AI quote (then POST /ai/run)
curl -X POST https://api.example.com/api/v1/ai/quote \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"ref": "tiktok:7300..."}'

AI

POST /api/v1/ai/quote returns the charge, POST /api/v1/ai/run starts a job, poll GET /api/v1/ai/jobs/{id}. Store watch phrases with PUT /api/v1/ai/{ref}/queries (up to three). Calling these with a token is consent to send comment texts to the model.

Keywords and alerts

GET and PUT /api/v1/keywords manage the account word list. Configure Telegram and HTTPS callbacks with GET / PUT /api/v1/notification-channels. Poll matches with GET /api/v1/keyword-alerts.

Job webhook

If job_events is on for the webhook channel (off by default), we POST when a job finishes: type is job.complete or job.failed, kind is analyze or ai, plus job_id, ref, url and error. Sign the body with HMAC in X-Signature as for keyword alerts.

Endpoints

MethodPathWhat
POST/api/v1/metadataFree post metadata
POST/api/v1/analyzeStart comment collection
GET/api/v1/analyze/{job_id}Poll the analyze job
POST/api/v1/sandbox/metadataMetadata fixture
POST/api/v1/sandbox/analyzeAnalyze fixture
GET/api/v1/usageLimits and comment balance
GET/api/v1/media/fileProxied cover and images
GET/api/v1/media/downloadDownload media as a file
POST/api/v1/analyses/{ref}/saveBookmark in the library
GET/api/v1/analyses/savedList saved posts
GET/api/v1/analyses/{ref}Load a saved analysis
DELETE/api/v1/analyses/{ref}Remove from the library
PUT/api/v1/analyses/{ref}/watchAuto-refresh
POST/api/v1/analyses/{ref}/refreshFull re-scrape now
GET/api/v1/analyses/sessionLatest session analysis
POST/api/v1/analyses/save-metadataSave metadata only
POST/api/v1/ai/quoteAI charge quote
POST/api/v1/ai/runStart AI job
GET/api/v1/ai/jobs/{id}Poll the AI job
PUT/api/v1/ai/{ref}/queriesWatch phrases
GET, PUT/api/v1/keywordsKeyword list
GET, PUT/api/v1/notification-channelsTelegram / webhook
GET/api/v1/keyword-alertsKeyword matches

Limits and quotas

LimitValue
Metadatasite: 10/day; token: 10 / 2 hours
Commentsby purchased packs (balance for the calendar month)
Comments per postup to 5,000
Concurrent analyses3

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. The free comment limit after signup works only in the workspace: with a token, analysis always comes from a pack.

Errors

Error body: {"detail": "...", "code": "machine_code"}

HTTPcodeWhen
401unauthorizedThe token is missing, revoked or invalid
403forbidden_scopeThe token lacks the required scope
402quota_exceededNo comments available — buy a pack
402payment_requiredA paid feature (watch, AI, keywords) needs a comment pack, or comments were not collected for this post yet
429rate_limitedRequest limit exceeded, see the Retry-After header
429concurrency_limitThree analyses are already running at once
400validation_errorInvalid URL or unsupported platform
422audience_restrictedThe author restricted the post audience
502parse_errorCould not fetch the post data
404not_foundThe job or analysis does not exist or belongs to another account