# Instagram Lead Gen

> Instagram data access via RapidAPI (instagram-social API). Use when querying Instagram for user profiles, followers, following lists, user posts, story highlights, post/reel/story details, comments, likes, searching users, hashtags, or general content. Also use when building, deploying, debugging, or extending this OfficeX app — understanding its REST API, AWS serverless architecture, OfficeX billing integration, NocoDB visual layer, or CDK infrastructure. Triggers on: instagram api, instagram search, instagram profile, instagram followers, instagram posts, instagram comments, instagram likes, instagram hashtags, instagram highlights, rapidapi instagram, instagram lead gen, instagram proxy, instagram worker, instagram dispatcher.

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

---


# Instagram RapidAPI Proxy — OfficeX App

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

| Environment | Base URL                                          | OfficeX API                          |
| ----------- | ------------------------------------------------- | ------------------------------------ |
| Production  | https://instagram-lead-gen-production.cloud.zoomgtm.com | https://cloud.officex.app/v1         |
| Staging     | https://instagram-lead-gen-staging.cloud.zoomgtm.com    | https://staging-backend.cloud.officex.app/v1 |

App ID (Production): 'b472aaf3-9b17-4d8c-b818-a6f8e2152eb5'

Single-vendor RapidAPI proxy wrapping 'instagram-social.p.rapidapi.com' as an OfficeX app. Serverless, AWS-native, scale-to-zero. See [TEMPLATE_ARCHITECTURE.md](TEMPLATE_ARCHITECTURE.md) for the full generic template this project implements.

## Instagram API Reference

See [.claude/skills/rapidapi-instagram/references/api_reference.md](.claude/skills/rapidapi-instagram/references/api_reference.md) for full endpoint docs with parameters and response schemas.

### Quick Reference

| Endpoint          | Path               | Required Param     | Paginated |
| ----------------- | ------------------ | ------------------ | --------- |
| 'search'          | '/search'          | 'search'           | no        |
| 'users-search'    | '/users/search'    | 'search'           | no        |
| 'hashtags-search' | '/hashtags/search' | 'search'           | no        |
| 'profile'         | '/profile'         | 'username'         | no        |
| 'followers'       | '/followers'       | 'username'         | yes       |
| 'following'       | '/following'       | 'username'         | yes       |
| 'posts'           | '/posts'           | 'username'         | yes       |
| 'highlights'      | '/highlights'      | 'username'         | no        |
| 'info'            | '/info'            | 'code' (shortcode) | no        |
| 'comments'        | '/comments'        | 'code' (shortcode) | yes       |
| 'likes'           | '/likes'           | 'code' (shortcode) | yes       |

### Authentication

'''
Headers:
X-RapidAPI-Key: {RAPID_API_KEY from .env}
X-RapidAPI-Host: instagram-social.p.rapidapi.com

Base URL: https://instagram-social.p.rapidapi.com/api/v1/instagram
Method: GET (all endpoints)
'''

### Response Format

'''json
{
"meta": { "version": "v1.0", "status": 200, "pagination_token": "..." | null },
"body": [ ... ] // array for list endpoints, object for /profile, /info
}
'''

Pagination: pass 'pagination_token' as query param for next page. 'null' = no more pages.

### Direct Usage

'''javascript
import 'dotenv/config';
const BASE = 'https://instagram-social.p.rapidapi.com/api/v1/instagram';
const headers = {
'x-rapidapi-key': process.env.RAPID_API_KEY,
'x-rapidapi-host': 'instagram-social.p.rapidapi.com'
};
const res = await fetch('{BASE}/profile?username=mrbeast', { headers });
const data = await res.json(); // data.meta, data.body
'''

## REST API (This App's Endpoints)

Auth for all job/status endpoints: 'x-officex-install-id' + 'x-officex-install-secret' headers.

### Submit Job

'''
POST /api/v1/jobs

// Single (quick queue):
{ "endpoint": "profile", "params": { "username": "mrbeast" }, "prompt_filter": "optional AI filter" }

// Batch (bulk queue):
{ "endpoint": "posts", "params": [{ "username": "a" }, { "username": "b" }], "max_records": 100 }

// Response (202):
{ "job_id": "...", "status": "queued", "total_tasks": 1, "credits_reserved": 1.01, "poll_url": "/api/v1/jobs/..." }
'''

### Poll & Results

'''
GET /api/v1/jobs/{job_id} — Job progress + cost breakdown
GET /api/v1/jobs/{job_id}/results — Paginated results (preview + match_score + S3 URLs)
GET /api/v1/jobs — List user's jobs
PATCH /api/v1/jobs/{job_id} — Cancel: { "status": "cancelled" }
'''

### Result Items & Bookmarks

'''
GET /api/v1/jobs/{job_id}/results/{task_index}/items/{item_index}
PATCH /api/v1/jobs/{job_id}/results/{task_index}/items/{item_index} — { "user_bookmarked": true, "user_notes": "..." }
GET /api/v1/jobs/{job_id}/result-rows — All bookmarks/notes for a job
'''

### Auth & Webhooks

'''
POST /auth/register — { email, password } → { api_key, install_id }
POST /auth/login — { email, password } → { api_key, install_id }
POST /auth/officex-login — { officex_customer_id, install_id, install_secret } → { api_key }
POST /webhooks/officex — INSTALL / UNINSTALL / RATE_LIMIT_CHANGE events
POST /api/v1/webhooks/nocodb — NocoDB 2-way sync (bookmark/notes)
GET / — Frontend HTML
GET /docs — API documentation
'''

## Architecture

'''
POST /api/v1/jobs → Ingress Lambda (validate + reserve credits + queue)
↓
┌──────────┴──────────┐
Quick Queue (80%) Bulk Queue (20%)
↓ ↓
Quick Dispatcher Bulk Dispatcher
└──────────┬──────────┘
Worker Lambda 1. Call Instagram API 2. Save to S3 (public URL, 90d) 3. Extract preview → DynamoDB 4. AI filter (Gemini) → match_score 5. Sip/Settle OfficeX credits 6. NocoDB sync (fire-and-forget) 7. Inbox notification on completion
'''

### Vendor Config

'''typescript
// infrastructure/lib/vendors.config.ts
{ id: "instagram", rateLimitMax: 20, rateLimitWindowSecs: 5 } // 4 req/sec safe margin
'''

### Pricing

- Base: **1.01 credits/task** (~$0.0101)
- With AI filter: **1.03 credits/task** (~$0.0103)
- Billing: Reserve → Sip → Settle pattern (see '/officex-developer' skill)

### Key Handlers

| File                         | Purpose                                                           |
| ---------------------------- | ----------------------------------------------------------------- |
| 'src/handlers/ingress.ts'    | API Gateway entry: auth, webhooks, job submission, credit reserve |
| 'src/handlers/worker.ts'     | API call, S3 storage, preview, AI filter, billing, pagination     |
| 'src/handlers/dispatcher.ts' | Rate budget check, async worker invoke (same code, 2 deployments) |
| 'src/handlers/status.ts'     | Job listing, results, cancel, frontend, NocoDB webhook            |
| 'src/handlers/auth.ts'       | Register, login, officex-login                                    |
| 'src/handlers/frontend.ts'   | HTML frontend renderer                                            |

### Key Libraries

| File                           | Purpose                                                                                  |
| ------------------------------ | ---------------------------------------------------------------------------------------- |
| 'src/lib/instagram-client.ts'  | Endpoint map, param validation, 'callInstagramApi()', 'RateLimitError'                   |
| 'src/lib/dynamo.ts'            | CRUD for Jobs, TaskResults, Users, RateBudget, ResultRows tables                         |
| 'src/lib/s3.ts'                | 'writeResult()', 'writeResultItems()' → public S3 URLs                                   |
| 'src/lib/officex-billing.ts'   | 'reserveCredits', 'sipCredits', 'settleCredits', 'cancelReservation', 'sendInboxMessage' |
| 'src/lib/gemini-filter.ts'     | AI scoring: Gemini 2.5 Flash Lite → '{ match_score: 0-100, ai_notes }'                   |
| 'src/lib/preview-extractor.ts' | Endpoint-specific flat preview extraction for DynamoDB                                   |
| 'src/lib/nocodb.ts'            | 'onInstall', 'onJobCreated', 'onTaskCompleted', 'onJobCompleted'                         |
| 'src/lib/rate-budget.ts'       | Sliding window rate limit tracker                                                        |
| 'src/lib/progressive-delay.ts' | Backoff schedule: 30s → 12h over 10+ retries                                             |

### DynamoDB Tables

| Table                          | Key                                           | TTL  |
| ------------------------------ | --------------------------------------------- | ---- |
| 'rapi-ig-{stage}-jobs'         | PK: 'job_id'                                  | 90d  |
| 'rapi-ig-{stage}-task-results' | PK: 'job_id', SK: 'task_index'                | 90d  |
| 'rapi-ig-{stage}-result-rows'  | PK: 'job_id', SK: '{task_index}#{item_index}' | 90d  |
| 'rapi-ig-{stage}-rate-budget'  | PK: 'vendor_id'                               | none |
| 'rapi-ig-{stage}-users'        | PK: 'install_id'                              | none |

### S3

Bucket: 'rapi-ig-{stage}-results-{account}' — public read, 90-day lifecycle, CORS enabled.
Objects: '{job_id}/{task_index}.json' (full response), '{job_id}/{task_index}/{item_index}.json' (individual items).

### NocoDB Results Tables

| Table              | Endpoints                                                  |
| ------------------ | ---------------------------------------------------------- |
| Results — Profiles | profile                                                    |
| Results — Posts    | posts, info, search                                        |
| Results — Users    | users-search, followers, following, likes, hashtags-search |
| Results — Comments | comments                                                   |

### Preview Extractor Fields (by endpoint)

- **profile**: username, full_name, is_verified, is_private, is_business, biography, followers, following, posts, category, external_url
- **posts/info**: shortcode, media_type, product_type, caption, like_count, comment_count, play_count, permalink, taken_at
- **followers/following**: result_count, username, full_name, is_verified, is_private
- **comments**: result_count, text, username
- **likes**: result_count, username, full_name, is_verified
- **highlights**: result_count, title, media_count
- **users-search**: result_count, username, full_name, is_verified, is_private
- **hashtags-search**: result_count, name, media_count

## Infrastructure (CDK)

'''
infrastructure/bin/app.ts — CDK app entry
infrastructure/lib/rapi-stack.ts — Main stack (all resources)
infrastructure/lib/app.config.ts — PROJECT_TAG = "rapidapi-proxy"
infrastructure/lib/vendors.config.ts — Single vendor: instagram
'''

### Deploy

'''bash

# Production (default — always use production)

npm run deploy:prod

# Register OfficeX app (production)

STAGE=production API_URL=https://instagram-lead-gen-production.cloud.zoomgtm.com npm run register:prod

# Staging (for development only)

npm run deploy:staging
npm run register:staging
'''

### Resources Created

4 Lambdas (ingress 256MB/30s, worker 512MB/60s, status 256MB/30s, 2× dispatcher 128MB/30s), 4 SQS FIFO queues + 4 DLQs, 5 DynamoDB tables, 1 S3 bucket, 1 CloudFront distribution, 1 HTTP API Gateway.

All tagged: 'app=rapi-ig-{stage}', 'project=rapidapi-proxy', 'vendor=instagram'.

## Environment Variables

'''env

# Required

RAPID_API_KEY= # RapidAPI key for instagram-social
GEMINI_API_KEY= # Gemini AI filter
AWS_ACCESS_KEY_ID= # AWS auth (use .env, not aws cli)
AWS_SECRET_ACCESS_KEY=
AWS_REGION=

# OfficeX

OFFICEX_USER_ID= # For app registration
OFFICEX_API_KEY= # For app registration

# NocoDB (optional — graceful degradation if missing)

NOCODB*HOST_URL=
NOCODB_TOKEN=
NOCODB_BASE=
NOCODB_TABLE_INSTALLS=
NOCODB_TABLE_JOBS=
NOCODB_TABLE_RESULTS_PROFILES=
NOCODB_TABLE_RESULTS_POSTS=
NOCODB_TABLE_RESULTS_USERS=
NOCODB_TABLE_RESULTS_COMMENTS=
NOCODB_FIELD*\*= # Link field IDs for views/filters
NOCODB_WEBHOOK_SECRET=
'''

## Auto-Pagination

Paginated endpoints (followers, following, posts, comments, likes) auto-follow cursors. User sets 'max_records' (default 100, max 1000). Worker queues follow-up tasks with incremented 'task_index' via atomic 'incrementTotalTasks()'. Credits reserved upfront for estimated total; final settle refunds unused.

## Job Lifecycle

'queued → processing → completed | failed | cancelled'

Also supports: 'processing → paused → processing (resume)'. Dispatcher and worker check status; paused tasks requeue with 60s delay.

## Error Handling

- **Rate limit (429)**: Progressive backoff requeue (30s → 12h), new dedup ID per retry
- **Real errors**: SQS natural retry (3 attempts), then DLQ (14-day retention)
- **Billing errors during sip/settle**: Logged, not fatal — result already saved
- **NocoDB errors**: Fire-and-forget, logged silently — AWS is source of truth

