# Tiktok Lead Gen

> TikTok data API with async job queue and optional AI filtering. 22 endpoints covering user profiles, videos, search, comments, hashtags, and trending data. Supports bulk operations and Gemini AI scoring via prompt_filter. Billed via OfficeX credits (0.04 credits/task, 0.05 with AI filter). Triggers on tiktok api, tiktok search, tiktok data, tiktok lead gen, tiktok scraping, tiktok user data, tokinsight, tiktok analytics, tiktok trending, tiktok profile, tiktok comments.

- Skill: `officexapp/tiktok-lead-gen` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add officexapp/tiktok-lead-gen`
- Raw SKILL.md: https://api.skillmd.com/api/skills/officexapp/tiktok-lead-gen/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: officexapp (https://skillmd.com/u/officexapp)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/officexapp/tiktok-lead-gen

---


# TikTok Data API

| Environment    | API / Frontend URL                                    |
| -------------- | ----------------------------------------------------- |
| **Production** | 'https://tiktok-lead-gen.cloud.zoomgtm.com'           |
| Staging        | 'https://tiktok-lead-gen-staging.cloud.zoomgtm.com'   |

**Production is ready and should always be used.**

## Authentication

Two auth methods are supported. All authenticated endpoints accept either.

### OfficeX Headers (recommended)

'''
x-officex-install-id: <install_id>
x-officex-install-secret: <install_secret>
'''

Credentials come from installing the app on OfficeX. AI agents receive 'api_key' and 'install_id' in 'agent_context' automatically on install.

### API Key

'''
x-api-key: <api_key>
'''

Obtained via '/auth/register' or '/auth/login'.

## Routes

| Method  | Path                                                            | Auth             | Description                                                |
| ------- | --------------------------------------------------------------- | ---------------- | ---------------------------------------------------------- |
| 'GET'   | '/'                                                             | None             | Web dashboard                                              |
| 'GET'   | '/docs'                                                         | None             | Raw SKILL.md as text                                       |
| 'POST'  | '/auth/register'                                                | None             | Register with email + password                             |
| 'POST'  | '/auth/login'                                                   | None             | Login with email + password                                |
| 'POST'  | '/auth/officex-login'                                           | None             | Auto-login via OfficeX creds                               |
| 'POST'  | '/webhooks/officex'                                             | OfficeX platform | Lifecycle webhooks (INSTALL, UNINSTALL, RATE_LIMIT_CHANGE) |
| 'POST'  | '/api/v1/jobs'                                                  | Required         | Create a job                                               |
| 'GET'   | '/api/v1/jobs'                                                  | Required         | List your jobs                                             |
| 'GET'   | '/api/v1/jobs/{job_id}'                                         | None             | Get job status                                             |
| 'PATCH' | '/api/v1/jobs/{job_id}'                                         | None             | Update job status (pause/cancel)                           |
| 'GET'   | '/api/v1/jobs/{job_id}/results'                                 | None             | Get paginated results                                      |
| 'GET'   | '/api/v1/jobs/{job_id}/results/{task_index}'                    | None             | Get single result                                          |
| 'GET'   | '/api/v1/jobs/{job_id}/result-rows'                             | None             | Get all bookmarks/notes for a job                          |
| 'PATCH' | '/api/v1/jobs/{job_id}/results/{task_index}/items/{item_index}' | None             | Update item bookmark/notes                                 |

## Auth Endpoints

### POST /auth/register

'''json
{ "email": "user@example.com", "password": "min6chars" }
'''

Returns '201': '{ "api*key": "rapi*...", "install*id": "email*...", "email": "..." }'

### POST /auth/login

'''json
{ "email": "user@example.com", "password": "..." }
'''

Returns '200': '{ "api*key": "rapi*...", "install_id": "...", "email": "..." }'

### POST /auth/officex-login

'''json
{
"officex_customer_id": "<user_id>",
"install_id": "<install_id>",
"install_secret": "<install_secret>"
}
'''

Returns '200' (existing user) or '201' (new user): '{ "api*key": "rapi*...", "install_id": "...", "install_secret": "..." }'

## POST /api/v1/jobs

Create a new async job. Each job runs one TikTok endpoint against one or many parameter sets.

### Request

'''json
{
"endpoint": "search-video",
"params": { "keyword": "fitness tips", "region": "US" },
"prompt_filter": "Looking for fitness influencers with high engagement",
"max_records": 100
}
'''

| Field           | Type            | Required | Description                                                                       |
| --------------- | --------------- | -------- | --------------------------------------------------------------------------------- |
| 'endpoint'      | string          | Yes      | One of the 22 TikTok endpoints (see below)                                        |
| 'params'        | object or array | Yes      | Parameters for the endpoint. Array for bulk jobs.                                 |
| 'prompt_filter' | string          | No       | AI filter prompt — enables Gemini scoring (0-100) on each result                  |
| 'max_records'   | number          | No       | Max items to fetch for paginated endpoints (1-1000, default 100). Auto-paginates. |

### Bulk jobs

Pass 'params' as an array to create multiple tasks in one job:

'''json
{
"endpoint": "search-video",
"params": [
{ "keyword": "fitness tips", "region": "US" },
{ "keyword": "cooking recipes", "region": "US" },
{ "keyword": "tech reviews", "region": "JP" }
]
}
'''

### Response '202'

'''json
{
"job_id": "a1b2c3d4-...",
"status": "queued",
"total_tasks": 3,
"estimated_total_tasks": 12,
"credits_reserved": 0.48,
"max_records": 100,
"poll_url": "/api/v1/jobs/a1b2c3d4-..."
}
'''

'estimated_total_tasks' accounts for auto-pagination (each page of ~25 results = 1 task).

### Errors

| Status | Code                 | Meaning                            |
| ------ | -------------------- | ---------------------------------- |
| '400'  | —                    | Missing/invalid endpoint or params |
| '401'  | —                    | Missing auth headers               |
| '402'  | 'INSUFFICIENT_FUNDS' | Not enough credits                 |
| '403'  | 'INSTALL_EXPIRED'    | OfficeX installation expired       |
| '429'  | 'RATE_LIMITED'       | Usage limit exceeded               |

## Endpoints (22)

### Profile (4)

| Endpoint         | Description                   | Required                          | Optional         |
| ---------------- | ----------------------------- | --------------------------------- | ---------------- |
| 'user-uniqueid'  | Look up user by username      | 'uniqueid'                        | —                |
| 'user-profile'   | Get profile by uid or sec_uid | 'uid' or 'sec_uid' (at least one) | 'uid', 'sec_uid' |
| 'user-following' | List accounts user follows    | 'uid', 'sec_uid'                  | 'cursor'         |
| 'user-follower'  | List user's followers         | 'uid', 'sec_uid'                  | 'cursor'         |

### Video (3)

| Endpoint              | Description           | Required         | Optional |
| --------------------- | --------------------- | ---------------- | -------- |
| 'video-detail'        | Get video details     | 'video_id'       | —        |
| 'user-video'          | List user's videos    | 'uid', 'sec_uid' | 'cursor' |
| 'user-favorite-video' | List user's favorites | 'uid', 'sec_uid' | 'cursor' |

### Search (8)

| Endpoint          | Description                 | Required  | Optional           |
| ----------------- | --------------------------- | --------- | ------------------ |
| 'search-trending' | Trending searches by region | 'region'  | —                  |
| 'search-video'    | Search videos               | 'keyword' | 'cursor', 'region' |
| 'search-user'     | Search users                | 'keyword' | 'cursor', 'region' |
| 'search-music'    | Search music/sounds         | 'keyword' | 'cursor', 'region' |
| 'search-hashtag'  | Search hashtags             | 'keyword' | 'cursor', 'region' |
| 'search-live'     | Search live streams         | 'keyword' | 'cursor', 'region' |
| 'search-photo'    | Search photo posts          | 'keyword' | 'cursor', 'region' |
| 'search-place'    | Search places               | 'keyword' | 'cursor', 'region' |

### Comment (2)

| Endpoint              | Description         | Required                 | Optional |
| --------------------- | ------------------- | ------------------------ | -------- |
| 'video-comment-list'  | Get video comments  | 'video_id'               | 'cursor' |
| 'video-comment-reply' | Get comment replies | 'video_id', 'comment_id' | 'cursor' |

### Hashtag (2)

| Endpoint         | Description              | Required                                      | Optional                     |
| ---------------- | ------------------------ | --------------------------------------------- | ---------------------------- |
| 'hashtag-detail' | Get hashtag details      | 'hashtag_id' or 'hashtag_name' (at least one) | 'hashtag_id', 'hashtag_name' |
| 'hashtag-video'  | Get videos for a hashtag | 'hashtag_id'                                  | 'cursor'                     |

### Creator Trending (3)

| Endpoint           | Description                 | Required | Optional |
| ------------------ | --------------------------- | -------- | -------- |
| 'trending-creator' | Trending creators by region | 'region' | —        |
| 'trending-topic'   | Trending topics by region   | 'region' | —        |
| 'trending-video'   | Trending videos by region   | 'region' | —        |

**Region codes**: 'US', 'GB', 'JP', 'BR', 'DE', 'FR', 'ID', 'IN', 'KR', 'MX', 'RU', 'TH', 'VN', etc.

## GET /api/v1/jobs

List your jobs, paginated.

| Param   | Default | Description   |
| ------- | ------- | ------------- |
| 'page'  | '1'     | Page number   |
| 'limit' | '20'    | Jobs per page |

### Response '200'

'''json
{
"jobs": [
{
"job_id": "a1b2c3d4-...",
"endpoint": "search-video",
"status": "completed",
"total_tasks": 3,
"completed_tasks": 3,
"failed_tasks": 0,
"created_at": "2025-01-30T22:00:00.000Z",
"prompt_filter": null,
"max_records": 100,
"credits_per_task": 0.04,
"reservation_id": "...",
"view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/...",
"nocodb_results_view_url": "https://..."
}
],
"next_page": null,
"nocodb_jobs_view_url": "https://..."
}
'''

## GET /api/v1/jobs/{job_id}

Poll job status.

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"vendor": "tokinsight",
"endpoint": "search-video",
"status": "processing",
"total_tasks": 3,
"completed_tasks": 1,
"failed_tasks": 0,
"created_at": "2025-01-30T22:00:00.000Z",
"updated_at": "2025-01-30T22:00:05.000Z",
"params": { "keyword": "fitness tips", "region": "US" },
"prompt_filter": "Looking for fitness influencers",
"max_records": 100,
"credits_per_task": 0.04,
"credits_charged": 0.04,
"latest_cursor": "30",
"reservation_id": "...",
"view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/...",
"nocodb_results_view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/...",
"warning": null
}
'''

- 'view_url' — Link to a NocoDB spreadsheet view of this job's results. Show this to the user so they can browse, filter, and sort results in a GUI. Same value as 'nocodb_results_view_url'.
- A 'warning' appears if a 'processing' job has had no progress for 5+ minutes.

### Job statuses

| Status       | Meaning                    |
| ------------ | -------------------------- |
| 'queued'     | Job accepted, tasks queued |
| 'processing' | Tasks being executed       |
| 'paused'     | Job paused by user         |
| 'completed'  | All tasks finished         |
| 'failed'     | Job failed                 |
| 'cancelled'  | Job cancelled              |

## PATCH /api/v1/jobs/{job_id}

Update a job's status.

'''json
{ "status": "paused" }
'''

### Valid transitions

| From         | Allowed targets           |
| ------------ | ------------------------- |
| 'queued'     | 'cancelled'               |
| 'processing' | 'paused', 'cancelled'     |
| 'paused'     | 'processing', 'cancelled' |
| 'completed'  | — (terminal)              |
| 'failed'     | — (terminal)              |
| 'cancelled'  | — (terminal)              |

### Response '200'

'''json
{ "job_id": "...", "status": "paused", "updated_at": "..." }
'''

## GET /api/v1/jobs/{job_id}/results

Get all results for a job, paginated.

| Param   | Default | Description      |
| ------- | ------- | ---------------- |
| 'page'  | '1'     | Page number      |
| 'limit' | '50'    | Results per page |

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"endpoint": "search-video",
"results": [
{
"task_index": 0,
"status": "completed",
"result_url": "https://s3.amazonaws.com/...",
"item_urls": ["https://s3.amazonaws.com/.../item-0.json", "..."],
"items": [
{
"desc": "Best workout routine for beginners",
"author_nickname": "FitCoach",
"author_unique_id": "fitcoach123",
"play_count": 150000,
"digg_count": 8500,
"comment_count": 320,
"tiktok_url": "https://www.tiktok.com/@fitcoach123/video/123456"
}
],
"error": null,
"match_score": 85,
"ai_notes": "Fitness creator with 500K followers discussing workout tips",
"credits_charged": 0.05
}
],
"next_page": null
}
'''

- 'items' — Parsed fields for each individual record extracted from the API response. One entry per TikTok result (video, user, comment, etc). Fields vary by endpoint type:
  - **Profile endpoints**: 'nickname', 'unique_id', 'follower_count', 'following_count', 'tiktok_url', 'avatar_thumb', 'avatar_url', ...
  - **Video endpoints**: 'desc', 'author_nickname', 'play_count', 'digg_count', 'comment_count', 'tiktok_url', 'cover_url', 'author_avatar', 'music_title', 'music_cover', 'duration', ...
  - **Comment endpoints**: 'text', 'comment_author', 'digg_count', 'reply_comment_total', 'author_avatar', ...
  - **Search endpoints**: 'title', 'desc', 'nickname', 'follower_count', 'view_count', 'avatar_url', ...
- 'result_url' — S3 URL to the full raw API response JSON
- 'item_urls' — S3 URLs to individual extracted items (for multi-result endpoints)
- 'match_score' (0-100) and 'ai_notes' — present only when 'prompt_filter' was set
- 'next_page' — next page number, or 'null' if no more results

## GET /api/v1/jobs/{job_id}/results/{task_index}

Get a single task result by 0-based index.

### Response '200'

'''json
{
"task_index": 0,
"status": "completed",
"result_url": "https://...",
"item_urls": ["https://..."],
"items": [{ "desc": "...", "author_nickname": "...", "play_count": 150000, "tiktok_url": "..." }],
"error": null,
"match_score": 85,
"ai_notes": "...",
"credits_charged": 0.05
}
'''

Returns '404' if the task has no result yet.

## GET /api/v1/jobs/{job_id}/result-rows

Get all user bookmarks and notes for a job. Returns a list of ResultRow objects from the separate result-rows DynamoDB table.

### Response '200'

'''json
{
"job_id": "abc-123",
"result_rows": [
{ "job_id": "abc-123", "sk": "0#3", "task_index": 0, "item_index": 3, "user_bookmarked": true, "user_notes": "Follow up", "updated_at": "2026-02-01T12:00:00Z", "ttl": 1743523200 }
]
}
'''

## PATCH /api/v1/jobs/{job_id}/results/{task_index}/items/{item_index}

Update bookmark/notes on an individual result item. Syncs to NocoDB automatically.

### Request

'''json
{
"user_bookmarked": true,
"user_notes": "Great engagement, follow up"
}
'''

| Field             | Type    | Required | Description                                    |
| ----------------- | ------- | -------- | ---------------------------------------------- |
| 'user_bookmarked' | boolean | No       | Bookmark this item (at least one field needed) |
| 'user_notes'      | string  | No       | Free-text notes for this item                  |

### Response '200'

Returns the ResultRow object:

'''json
{
"job_id": "abc-123",
"sk": "0#3",
"task_index": 0,
"item_index": 3,
"user_bookmarked": true,
"user_notes": "Great engagement, follow up",
"updated_at": "2026-02-01T12:00:00Z",
"ttl": 1743523200
}
'''

## Billing

| Operation              | Credits | USD equivalent |
| ---------------------- | ------- | -------------- |
| Task without AI filter | 0.04    | $0.0004        |
| Task with AI filter    | 0.05    | $0.0005        |

Credits are reserved upfront when the job is created. Failed tasks are not billed. Unused reserved credits are refunded when the job completes.

For paginated endpoints, each page of ~25 results counts as one task. A 'max_records: 100' job with 1 param set reserves 'ceil(100/25) \* 0.04 = 0.16' credits.

## Data Retention

Results are stored in S3 for **90 days** and automatically expire.

## Typical Flow

**AI Agents: Always share the 'view_url' with the user.** It links to an interactive spreadsheet where they can browse, filter, and sort all results — much easier than reading JSON.

'''

1. POST /api/v1/jobs → get job_id + poll_url
2. GET /api/v1/jobs/{job_id} → poll until status is "completed"
   - The response includes 'view_url' — **always share this link with the user** so they can view results in a spreadsheet GUI
3. GET /api/v1/jobs/{job_id}/results → fetch all results (items array has parsed fields per record)
   '''

## Examples

### Search TikTok videos

'''bash
curl -X POST https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs \
 -H "Content-Type: application/json" \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET" \
 -d '{"endpoint":"search-video","params":{"keyword":"fitness tips","region":"US"},"max_records":50}'
'''

### Look up a TikTok user by username

'''bash
curl -X POST https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs \
 -H "Content-Type: application/json" \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET" \
 -d '{"endpoint":"user-uniqueid","params":{"uniqueid":"charlidamelio"}}'
'''

### Bulk search with AI filter

'''bash
curl -X POST https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs \
 -H "Content-Type: application/json" \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET" \
 -d '{
"endpoint": "search-user",
"params": [
{"keyword": "fitness coach", "region": "US"},
{"keyword": "personal trainer", "region": "US"}
],
"prompt_filter": "Looking for fitness professionals with 10K+ followers who post regularly",
"max_records": 200
}'
'''

### Poll and fetch results

'''bash

# Poll status

curl https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs/JOB_ID \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET"

# Get results

curl https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs/JOB_ID/results \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET"

# Pause a running job

curl -X PATCH https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs/JOB_ID \
 -H "Content-Type: application/json" \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET" \
 -d '{"status":"paused"}'

# Cancel a job

curl -X PATCH https://46n9u415sc.execute-api.us-east-1.amazonaws.com/api/v1/jobs/JOB_ID \
 -H "Content-Type: application/json" \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET" \
 -d '{"status":"cancelled"}'
'''

### Frontend (web dashboard)

Visit 'GET /' for the web UI. Supports OfficeX autologin via URL params:

'''
https://tiktok-lead-gen.cloud.zoomgtm.com?officex_customer_id=X&officex_install_id=Y&officex_install_secret=Z
'''

### Common workflows

**Find influencers in a niche:**

1. 'search-user' with keyword + AI filter for follower count/engagement
2. 'user-profile' on top matches to get full stats
3. 'user-video' to analyze recent content

**Monitor trending content:**

1. 'trending-video' or 'trending-topic' with region
2. 'video-detail' on interesting videos
3. 'video-comment-list' to gauge audience reaction

**Hashtag research:**

1. 'search-hashtag' with keyword
2. 'hashtag-detail' for view counts
3. 'hashtag-video' to see top content

