# Reddit Lead Gen

> Reddit data API with AI filtering. Search posts, get subreddit info, user stats, and comments via a job-based async API. Supports bulk operations, auto-pagination, and optional Gemini AI scoring with prompt_filter. Billed via OfficeX credits (~1 credit per task). Use when querying Reddit for subreddit posts, searching Reddit content, getting post details with comments, subreddit info, popular/new subreddits, subreddit comments, user stats, or user activity data. Triggers on reddit api, reddit search, subreddit posts, reddit user stats, reddit comments, reddit data, reddit lead gen, reddit scraping.

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

---


# Reddit Lead Gen API

Async job-based REST API for Reddit data. Submit a job, poll for status, fetch results.

## Base URL

| Environment | URL                                                      |
| ----------- | -------------------------------------------------------- |
| Staging     | 'https://reddit-lead-gen-staging.cloud.zoomgtm.com' |
| Production  | 'https://reddit-lead-gen-production.cloud.zoomgtm.com' |

> **Production is live.** Use the production URL for all real usage.

## Authentication

### OfficeX Headers (primary)

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

Required for 'POST /api/v1/jobs'. Credentials come from OfficeX app install ('agent_context' contains 'api_key' and 'install_id').

### API Key (read-only endpoints)

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

Works for 'GET' endpoints (list jobs, get results). Obtained via '/auth/register', '/auth/login', or the OfficeX install webhook.

### Auth Endpoints

| Method | Path                  | Body                                                        | Description                       |
| ------ | --------------------- | ----------------------------------------------------------- | --------------------------------- |
| 'POST' | '/auth/register'      | '{ "email", "password" }'                                   | Create account, returns 'api_key' |
| 'POST' | '/auth/login'         | '{ "email", "password" }'                                   | Login, returns 'api_key'          |
| 'POST' | '/auth/officex-login' | '{ "officex_customer_id", "install_id", "install_secret" }' | Auto-login via OfficeX            |

## Core Flow

'''

1. POST /api/v1/jobs -> get job_id + poll_url
2. GET /api/v1/jobs/{id} -> poll until status is "completed"
3. GET /api/v1/jobs/{id}/results -> fetch results
   '''

**AI Agents: Always share the 'view_url' with your human.** When you poll job status, the response includes a 'view_url' — a NocoDB spreadsheet GUI where your human can browse, filter, and sort results visually. Present this link whenever you report job status or completion. Example: "Your job is complete. [View results in spreadsheet](view_url)"

## Routes

| Method  | Path                                                            | Description                |
| ------- | --------------------------------------------------------------- | -------------------------- |
| 'GET'   | '/'                                                             | Web dashboard              |
| 'GET'   | '/docs'                                                         | Raw API docs (this file)   |
| 'POST'  | '/auth/register'                                                | Register account           |
| 'POST'  | '/auth/login'                                                   | Login                      |
| 'POST'  | '/auth/officex-login'                                           | OfficeX autologin          |
| 'POST'  | '/webhooks/officex'                                             | OfficeX lifecycle webhooks |
| 'POST'  | '/api/v1/jobs'                                                  | Create a job               |
| 'GET'   | '/api/v1/jobs'                                                  | List user's jobs           |
| 'GET'   | '/api/v1/jobs/{job_id}'                                         | Get job status             |
| 'PATCH' | '/api/v1/jobs/{job_id}'                                         | Update job status          |
| 'GET'   | '/api/v1/jobs/{job_id}/results'                                 | Get all results            |
| 'GET'   | '/api/v1/jobs/{job_id}/results/{task_index}'                    | Get single result          |
| 'PATCH' | '/api/v1/jobs/{job_id}/results/{task_index}/items/{item_index}' | Bookmark/annotate item     |
| 'GET'   | '/api/v1/jobs/{job_id}/result-rows'                             | Get all bookmarks/notes    |

---

## POST /api/v1/jobs

Create a new job. Auth: OfficeX headers required.

### Request

'''json
{
"endpoint": "search",
"params": { "search": "ai startups", "subreddit": "technology" },
"prompt_filter": "Looking for posts from SaaS founders discussing pricing",
"max_records": 100
}
'''

| Field           | Type            | Required | Description                                             |
| --------------- | --------------- | -------- | ------------------------------------------------------- |
| 'endpoint'      | string          | yes      | One of the 9 endpoints below                            |
| 'params'        | object or array | yes      | Single param set or array for bulk                      |
| 'prompt_filter' | string          | no       | AI filter prompt — scores results 0-100 with notes      |
| 'max_records'   | number          | no       | Max items for paginated endpoints (1-1000, default 100) |

### Bulk Jobs

Pass 'params' as an array:

'''json
{
"endpoint": "subreddit-info",
"params": [
{ "subreddit": "technology" },
{ "subreddit": "startups" },
{ "subreddit": "SaaS" }
]
}
'''

### Response '202'

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

### Errors

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

---

## Endpoints & Parameters

### 'search' (paginated)

Search Reddit posts within a subreddit.

| Param        | Required | Description         |
| ------------ | -------- | ------------------- |
| 'search'     | yes      | Search query        |
| 'subreddit'  | yes      | Subreddit to search |
| 'filter'     | no       | Filter type         |
| 'timeFilter' | no       | Time range filter   |
| 'sortType'   | no       | Sort order          |
| 'cursor'     | no       | Pagination cursor   |

### 'posts' (paginated)

Get posts from a Reddit URL.

| Param    | Required | Description       |
| -------- | -------- | ----------------- |
| 'url'    | yes      | Reddit URL        |
| 'filter' | no       | Filter type       |
| 'cursor' | no       | Pagination cursor |

### 'post'

Get a single post with comments.

| Param | Required | Description |
| ----- | -------- | ----------- |
| 'url' | yes      | Post URL    |

### 'subreddit-info'

Get subreddit metadata.

| Param       | Required | Description    |
| ----------- | -------- | -------------- |
| 'subreddit' | yes      | Subreddit name |

### 'subreddit-popular' (paginated)

List popular subreddits.

| Param    | Required | Description       |
| -------- | -------- | ----------------- |
| 'cursor' | no       | Pagination cursor |

### 'subreddit-new' (paginated)

List new subreddits.

| Param    | Required | Description       |
| -------- | -------- | ----------------- |
| 'cursor' | no       | Pagination cursor |

### 'subreddit-comments' (paginated)

Get comments from a subreddit.

| Param       | Required | Description       |
| ----------- | -------- | ----------------- |
| 'subreddit' | yes      | Subreddit name    |
| 'cursor'    | no       | Pagination cursor |

### 'user-stats'

Get stats for a Reddit user.

| Param      | Required | Description     |
| ---------- | -------- | --------------- |
| 'username' | yes      | Reddit username |

### 'user-data' (paginated)

Get activity data for a Reddit user.

| Param      | Required | Description       |
| ---------- | -------- | ----------------- |
| 'username' | yes      | Reddit username   |
| 'filter'   | no       | Filter type       |
| 'sortType' | no       | Sort order        |
| 'cursor'   | no       | Pagination cursor |

---

## GET /api/v1/jobs

List user's jobs. Auth: 'x-api-key' or 'x-officex-install-id'.

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

### Response '200'

'''json
{
"view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/...",
"jobs": [
{
"job_id": "a1b2c3d4-...",
"endpoint": "search",
"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": 1.01,
"view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/..."
}
],
"next_page": null
}
'''

- Top-level 'view_url': NocoDB shared view of all the user's jobs (GUI dashboard) — share with your human so they can track all jobs
- Per-job 'view_url': NocoDB shared view filtered to that job's results — **always share this link with your human** so they can browse results in a spreadsheet GUI

---

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

Poll job status.

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"vendor": "reddit",
"endpoint": "search",
"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": { "search": "ai startups", "subreddit": "technology" },
"prompt_filter": null,
"max_records": 100,
"credits_per_task": 1.01,
"credits_charged": 2.02,
"latest_cursor": "t3_abc123",
"view_url": "https://dgamh7nm.rpcld.co/dashboard/#/nc/view/...",
"warning": null
}
'''

- 'view_url': NocoDB shared view of this job's results — **always present this link to your human** so they can browse, filter, and sort results in a spreadsheet GUI
- 'warning' appears when a 'processing' job has had no progress for 5+ minutes.

### Job Statuses

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

### State Transitions

- 'queued' -> 'cancelled'
- 'processing' -> 'paused', 'cancelled'
- 'paused' -> 'processing', 'cancelled'
- 'completed', 'failed', 'cancelled' -> (terminal, no transitions)

---

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

Update job status. Only valid transitions allowed.

### Request

'''json
{ "status": "cancelled" }
'''

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"status": "cancelled",
"updated_at": "2025-01-30T22:01:00.000Z"
}
'''

---

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

Get all results, paginated.

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

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"endpoint": "search",
"results": [
{
"task_index": 0,
"status": "completed",
"result_url": "https://rapi-prod-results-994816277608.s3.amazonaws.com/...",
"item_urls": ["https://...item0.json", "https://...item1.json"],
"error": null,
"match_score": 85,
"ai_notes": "Post discusses SaaS pricing from a founder's perspective",
"credits_charged": 1.01
}
],
"next_page": null
}
'''

- 'result_url': S3 URL to the full raw API response JSON
- 'item_urls': S3 URLs to individual unwrapped items (one per post/comment/user)
- 'match_score' (0-100) and 'ai_notes': present when 'prompt_filter' was set
- 'next_page': null when no more pages

---

## 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://..."],
"error": null,
"match_score": 85,
"ai_notes": "Relevant post about SaaS pricing",
"credits_charged": 1.01
}
'''

Returns '404' if result not yet available.

---

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

Bookmark or annotate an individual result item. At least one of 'user_bookmarked' or 'user_notes' is required.

### Request

'''json
{
"user_bookmarked": true,
"user_notes": "Great lead — follow up next week"
}
'''

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"sk": "0#3",
"task_index": 0,
"item_index": 3,
"user_bookmarked": true,
"user_notes": "Great lead — follow up next week",
"updated_at": "2025-01-30T22:05:00.000Z",
"ttl": 1745000000
}
'''

- Creates on first write, updates on subsequent writes
- Also syncs to NocoDB (fire-and-forget)
- Returns '400' if both fields missing or 'item_index' out of range
- Returns '404' if job or task result not found

---

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

Get all bookmarks and notes for a job. Only items that have been bookmarked or annotated are returned.

### Response '200'

'''json
{
"job_id": "a1b2c3d4-...",
"result_rows": [
{
"job_id": "a1b2c3d4-...",
"sk": "0#3",
"task_index": 0,
"item_index": 3,
"user_bookmarked": true,
"user_notes": "Great lead",
"updated_at": "2025-01-30T22:05:00.000Z"
}
]
}
'''

---

## Webhooks (OfficeX Platform)

'POST /webhooks/officex' receives lifecycle events from OfficeX.

| Event               | Description                                                                       |
| ------------------- | --------------------------------------------------------------------------------- |
| 'INSTALL'           | New install — creates user, returns 'agent_context' with 'api_key' + 'install_id' |
| 'UNINSTALL'         | Deactivates the user                                                              |
| 'RATE_LIMIT_CHANGE' | Rate limit updated (logged, not enforced in-app)                                  |

---

## Billing

Credits are reserved upfront, settled progressively as tasks complete, remainder refunded.

| Scenario             | Credits/task |
| -------------------- | ------------ |
| Without AI filter    | 1.01         |
| With 'prompt_filter' | 1.03         |

For paginated endpoints, credits are reserved for estimated total pages ('ceil(max*records / 25) * params*count * credits_per_task'). Failed tasks are not billed. Unused credits are refunded on job completion.

## Data Retention

Results stored for **90 days**, then auto-expire.

---

## Examples

### Search subreddit

'''bash
curl -X POST https://reddit-lead-gen-production.cloud.zoomgtm.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","params":{"search":"ai tools","subreddit":"technology"}}'
'''

### Search with AI filter

'''bash
curl -X POST https://reddit-lead-gen-production.cloud.zoomgtm.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","params":{"search":"crm software","subreddit":"smallbusiness"},"prompt_filter":"Find posts from business owners frustrated with their current CRM"}'
'''

### Bulk subreddit info

'''bash
curl -X POST https://reddit-lead-gen-production.cloud.zoomgtm.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":"subreddit-info","params":[{"subreddit":"startups"},{"subreddit":"SaaS"},{"subreddit":"Entrepreneur"}]}'
'''

### Poll status

'''bash
curl https://reddit-lead-gen-production.cloud.zoomgtm.com/api/v1/jobs/$JOB_ID \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET"
'''

### Get results

'''bash
curl https://reddit-lead-gen-production.cloud.zoomgtm.com/api/v1/jobs/$JOB_ID/results \
 -H "x-officex-install-id: $INSTALL_ID" \
 -H "x-officex-install-secret: $INSTALL_SECRET"
'''

### Cancel a job

'''bash
curl -X PATCH https://reddit-lead-gen-production.cloud.zoomgtm.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"}'
'''

