# X Lead Gen

> Async job-based REST API for Twitter/X data extraction with optional AI filtering. Search tweets, get user profiles, followers, timelines, trends, job listings, spaces, and communities via 29 endpoints. Supports bulk operations, auto-pagination, and Gemini 2.5 Flash Lite scoring. Billed via OfficeX credits. Use when: (1) Searching Twitter for leads, prospects, or market research, (2) Looking up Twitter user profiles or follower/following lists, (3) Getting tweet details, threads, replies, or retweets, (4) Finding trending topics, job listings, or community data, (5) Any Twitter/X data retrieval task. Triggers on: twitter api, twitter search, twitter lead gen, twitter user data, tweet search, twitter trends, twitter spaces, twitter followers, x api.

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

---


# Twitter Lead Gen API

Async job-based API. Submit a job, poll for status, retrieve results.

**Important:** When a job's 'view_url' is available, always share it with the user — it opens a spreadsheet GUI where they can browse, sort, and filter results visually.

## Base URL

```
https://x-lead-gen-api-production.cloud.zoomgtm.com
```

## Authentication

Two options (send one):

| Header                                              | Source                                 |
| --------------------------------------------------- | -------------------------------------- |
| 'x-officex-install-id' + 'x-officex-install-secret' | OfficeX install                        |
| 'x-api-key'                                         | From '/auth/register' or '/auth/login' |

## Core Workflow

'''
POST /api/v1/jobs → 202 { job_id, status: "queued" }
GET /api/v1/jobs/{job_id} → 200 { status: "processing"|"completed", ... }
GET /api/v1/jobs/{job_id}/results → 200 { results: [...] }
'''

### 1. Create Job

'''bash
curl -X POST $BASE/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",
"params": { "query": "AI startups" },
"max_records": 100
}'
'''

**Request body:**

'''json
{
"endpoint": "search",
"params": { "query": "AI startups" },
"prompt_filter": "SaaS founders discussing pricing",
"max_records": 100
}
'''

| Field           | Type            | Required | Description                                                                    |
| --------------- | --------------- | -------- | ------------------------------------------------------------------------------ |
| 'endpoint'      | string          | Yes      | One of 29 endpoints below                                                      |
| 'params'        | object or array | Yes      | Endpoint params. Array for bulk (one task per item)                            |
| 'prompt_filter' | string          | No       | AI filter prompt (adds Gemini scoring, costs 0.12 instead of 0.1 credits/task) |
| 'max_records'   | number          | No       | 1-1000, default 100. Auto-paginates to fetch this many results                 |

**Response (202):**

'''json
{
"job_id": "uuid",
"status": "queued",
"total_tasks": 4,
"credits_reserved": 0.4,
"poll_url": "/api/v1/jobs/{job_id}"
}
'''

### 2. Poll Status

'''bash
curl $BASE/api/v1/jobs/{job_id} -H "x-api-key: $KEY"
'''

**Response:**

'''json
{
"job_id": "uuid",
"endpoint": "search",
"status": "completed",
"total_tasks": 4,
"completed_tasks": 4,
"failed_tasks": 0,
"credits_per_task": 0.1,
"credits_charged": 0.4,
"params": { "query": "AI startups" },
"max_records": 100,
"latest_cursor": "...",
"created_at": "2025-01-25T10:00:00Z",
"view_url": "https://example.com/dashboard/#/nc/view/uuid"
}
'''

'view_url' — opens a spreadsheet GUI (NocoDB) showing results for this job. Present it to the user so they can browse results visually. Only present once the job has started processing.

Status values: 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled' | 'paused'

### 3. Get Results

'''bash
curl "$BASE/api/v1/jobs/{job_id}/results?page=1&limit=50" -H "x-api-key: $KEY"
'''

**Response:**

'''json
{
"job_id": "uuid",
"endpoint": "search",
"results": [
{
"task_index": 0,
"status": "success",
"result_url": "https://s3.amazonaws.com/...",
"item_urls": ["https://s3.amazonaws.com/..."],
"credits_charged": 0.1,
"match_score": 85,
"ai_notes": "SaaS founder discussing B2B pricing"
}
],
"next_page": 2
}
'''

'result_url' — full API response JSON. 'item_urls' — individual items (one per tweet/user/etc). 'match_score' and 'ai_notes' only present when 'prompt_filter' was used.

### 4. Control Jobs

'''bash

# Pause

curl -X PATCH $BASE/api/v1/jobs/{job_id} \
 -H "x-api-key: $KEY" -H "Content-Type: application/json" \
 -d '{"status": "paused"}'

# Resume

curl -X PATCH ... -d '{"status": "processing"}'

# Cancel

curl -X PATCH ... -d '{"status": "cancelled"}'
'''

Valid transitions: 'processing' → 'paused' → 'processing', any active → 'cancelled'.

### 5. Bookmark & Notes (per-item annotations)

Save bookmarks and notes on individual result items. Annotations persist in DynamoDB (result-rows table) and sync to the NocoDB spreadsheet view.

'''bash

# Get all result rows (annotations) for a job

curl "$BASE/api/v1/jobs/{job_id}/result-rows" -H "x-api-key: $KEY"
'''

**Response:**

'''json
{
"result_rows": [
{ "job_id": "uuid", "sk": "0#0", "task_index": 0, "item_index": 0, "user_bookmarked": true, "user_notes": "Great lead", "updated_at": "...", "ttl": 1234567890 },
{ "job_id": "uuid", "sk": "0#3", "task_index": 0, "item_index": 3, "user_bookmarked": false, "user_notes": "Follow up later", "updated_at": "...", "ttl": 1234567890 }
]
}
'''

'''bash

# Bookmark or add notes to an item

curl -X PATCH "$BASE/api/v1/jobs/{job_id}/results/0/items/3" \
 -H "x-api-key: $KEY" -H "Content-Type: application/json" \
 -d '{"user_bookmarked": true, "user_notes": "Promising SaaS founder"}'
'''

**Response:**

'''json
{
"success": true,
"job_id": "uuid",
"task_index": 0,
"item_index": 3,
"user_bookmarked": true,
"user_notes": "Promising SaaS founder"
}
'''

Both fields are optional — send either or both. 'view_url' spreadsheet includes 'user_bookmarked' and 'user_notes' columns that sync automatically.

### 5b. NocoDB Webhook (2-way sync)

'''bash

# NocoDB calls this when a user edits annotations in the spreadsheet

curl -X POST "$BASE/api/v1/webhooks/nocodb" \
 -H "x-webhook-secret: $NOCODB_WEBHOOK_SECRET" \
 -H "Content-Type: application/json" \
 -d '{"data":{"row":{"job_id":"uuid","task_index":0,"item_index":3,"user_bookmarked":true}}}'
'''

Anti-loop: webhook writes to DynamoDB only, never syncs back to NocoDB.

### 5c. Legacy Endpoints (deprecated)

The following endpoints still work but are deprecated. Use the new endpoints above.

'''bash

# DEPRECATED: Get annotations (use GET /result-rows instead)

curl "$BASE/api/v1/jobs/{job_id}/items" -H "x-api-key: $KEY"

# DEPRECATED: Patch annotation (use PATCH /results/{task_index}/items/{item_index} instead)

curl -X PATCH "$BASE/api/v1/jobs/{job_id}/items/0:3" \
 -H "x-api-key: $KEY" -H "Content-Type: application/json" \
 -d '{"user_bookmarked": true}'
'''

## Endpoints (29)

### User Endpoints

| Endpoint        | Required           | Optional              | Returns                |
| --------------- | ------------------ | --------------------- | ---------------------- |
| 'user-info'     | screenname         | rest_id               | Single user profile    |
| 'bulk-users'    | rest_ids           | —                     | Multiple user profiles |
| 'about-profile' | screenname         | —                     | Extended profile info  |
| 'following'     | screenname         | cursor                | Paginated user list    |
| 'followers'     | screenname         | blue_verified, cursor | Paginated user list    |
| 'affiliates'    | screenname         | cursor                | Paginated user list    |
| 'check-follow'  | screenname, target | —                     | Follow relationship    |

### Tweet Endpoints

| Endpoint         | Required       | Optional            | Returns                |
| ---------------- | -------------- | ------------------- | ---------------------- |
| 'search'         | query          | search_type, cursor | Paginated tweets       |
| 'timeline'       | screenname     | cursor              | Paginated tweets       |
| 'usermedia'      | screenname     | cursor              | Paginated media tweets |
| 'replies'        | screenname     | cursor              | Paginated replies      |
| 'tweet-info'     | id             | —                   | Single tweet           |
| 'tweet-thread'   | id             | —                   | Tweet thread           |
| 'latest-replies' | id             | cursor              | Paginated replies      |
| 'retweets'       | id             | cursor              | Paginated users        |
| 'check-retweet'  | id, screenname | —                   | Retweet check          |
| 'top-posts'      | type           | country, period     | Paginated tweets       |

'search_type': Top, Latest, People, Photos, Videos. 'type' (top-posts): Likes, Retweets. 'period': Daily, Weekly, Monthly.

### List Endpoints

| Endpoint         | Required | Optional | Returns          |
| ---------------- | -------- | -------- | ---------------- |
| 'list-timeline'  | list_id  | cursor   | Paginated tweets |
| 'list-followers' | list_id  | cursor   | Paginated users  |
| 'list-members'   | list_id  | cursor   | Paginated users  |

### Community Endpoints

| Endpoint             | Required     | Optional        | Returns          |
| -------------------- | ------------ | --------------- | ---------------- |
| 'community-timeline' | community_id | ranking, cursor | Paginated tweets |
| 'community-members'  | community_id | cursor          | Paginated users  |
| 'search-communities' | query        | —               | Community list   |
| 'communities-latest' | query        | cursor          | Paginated tweets |
| 'communities-top'    | query        | cursor          | Paginated tweets |

'ranking': Top, New.

### Other Endpoints

| Endpoint    | Required | Optional | Returns         |
| ----------- | -------- | -------- | --------------- |
| 'trends'    | country  | —        | Trending topics |
| 'jobs'      | query    | —        | Job listings    |
| 'spaces'    | id       | —        | Space details   |
| 'broadcast' | rest_id  | —        | Broadcast info  |

## Bulk Requests

Pass 'params' as an array to create one task per item:

'''json
{
"endpoint": "user-info",
"params": [
{ "screenname": "elonmusk" },
{ "screenname": "sama" },
{ "screenname": "sataborasu" }
]
}
'''

Creates 3 tasks. Each task is billed independently.

## Billing

| Type                 | Credits/Task | USD/Task |
| -------------------- | ------------ | -------- |
| Without AI filter    | 0.1          | $0.001   |
| With 'prompt_filter' | 0.12         | $0.0012  |

Credits are reserved upfront, settled progressively as tasks complete. Failed tasks are not billed. Unused credits are refunded on completion/cancellation.

## Auth Endpoints

### POST '/auth/register'

'''json
{ "email": "user@example.com", "password": "min6chars" }
'''
→ '201 { api_key, install_id, email }'

### POST '/auth/login'

'''json
{ "email": "user@example.com", "password": "..." }
'''
→ '200 { api_key, install_id, email }'

### POST '/auth/officex-login'

'''json
{ "officex_customer_id": "uuid", "install_id": "uuid", "install_secret": "..." }
'''
→ '200 { api_key, install_id, install_secret }'

## All Routes

| Method | Path                                                            | Description                               |
| ------ | --------------------------------------------------------------- | ----------------------------------------- |
| POST   | '/auth/register'                                                | Create account                            |
| POST   | '/auth/login'                                                   | Login                                     |
| POST   | '/auth/officex-login'                                           | OfficeX autologin                         |
| POST   | '/api/v1/jobs'                                                  | Create job                                |
| GET    | '/api/v1/jobs'                                                  | List jobs ('?page=&limit=')               |
| GET    | '/api/v1/jobs/{job_id}'                                         | Job status                                |
| PATCH  | '/api/v1/jobs/{job_id}'                                         | Update job (pause/resume/cancel)          |
| GET    | '/api/v1/jobs/{job_id}/results'                                 | Results ('?page=&limit=')                 |
| GET    | '/api/v1/jobs/{job_id}/results/{task_index}'                    | Single result                             |
| GET    | '/api/v1/jobs/{job_id}/result-rows'                             | Get all result rows (annotations)         |
| PATCH  | '/api/v1/jobs/{job_id}/results/{task_index}/items/{item_index}' | Update item bookmark/notes                |
| POST   | '/api/v1/webhooks/nocodb'                                       | NocoDB 2-way sync webhook                 |
| GET    | '/api/v1/jobs/{job_id}/items'                                   | _Deprecated_ — Get item annotations       |
| PATCH  | '/api/v1/jobs/{job_id}/items/{item_key}'                        | _Deprecated_ — Update item bookmark/notes |
| GET    | '/docs'                                                         | Raw skill markdown                        |
| POST   | '/webhooks/officex'                                             | OfficeX lifecycle webhooks                |

## Error Codes

| Code | Meaning                            |
| ---- | ---------------------------------- |
| 400  | Invalid request (validation error) |
| 401  | Missing or invalid auth            |
| 402  | Insufficient credits               |
| 403  | Installation expired               |
| 404  | Job or result not found            |
| 409  | Email already registered           |
| 429  | Rate limited                       |

All errors return: '{ "error": "Human-readable message" }'

## Data Retention

Results stored for 90 days in S3.

