Report Creation Pipeline
This guide provides a detailed explanation of each step in the report creation process, including all available options and edge cases.
Pipeline Overview
Step 1: Create Report
Search by Username
The most common method - search for a specific social media account:
POST /create
{
"source": "ig",
"username": "username_to_search"
}
Available sources:
| Source | Platform | Notes |
|---|---|---|
ig | Most comprehensive data | |
tw | Good for public figures | |
fb | Limited to public profiles | |
tt | TikTok | Growing coverage |
li | Professional profiles |
Search by Name (US Only)
Search by person's name and state:
POST /create
{
"name": "John Smith",
"state": "CA"
}
This searches across all social networks to find matching profiles.
Response
{
"id": "68af01be012b843fd7bc2bf4"
}
The report ID is a 24-character string. Save it for all subsequent calls.
Step 2: Get Search Results
Get All Sources
GET /create/{reportId}
Returns profiles from all social networks at once.
Get Specific Source
GET /create/{reportId}/{source}?limit=20&offset=0
Paginated results for a specific source.
Search Within Source
If the profile wasn't found, search directly:
POST /create/{reportId}/{source}/search
{
"username": "exact_username"
}
Profile Status
Each profile can have a badReason indicating why it can't be analyzed:
| Reason | Description |
|---|---|
private | Profile is private |
notFound | Profile doesn't exist |
zeroFollows | Profile follows no one |
optOut | User requested data removal |
unloaded | Data not yet loaded |
unmapped | Profile could not be mapped |
unexpected | Unexpected failure |
Step 3: Add Profiles
Add profiles one by one to your report:
POST /create/{reportId}/{source}/add
{
"id": "profile_id"
}
Response
{
"added": true,
"unloaded": false,
"status": {
"type": "follows",
"status": "inited",
"id": "profile_id",
"source": "ig"
}
}
Status Values
inited- Profile queued for loadinginprogress- Loading in progressdone- Data loaded successfullyerror- Loading failed
Adding Multiple Sources
You can add profiles from multiple sources to a single report:
# Add Instagram profile
POST /create/{reportId}/ig/add
{"id": "ig_profile_id"}
# Add Twitter profile
POST /create/{reportId}/tw/add
{"id": "tw_profile_id"}
Step 4: Confirm Selection
Lock in your profile selection and start data loading:
POST /create/{reportId}/confirm
[
{"source": "ig", "id": "ig_profile_id"},
{"source": "tw", "id": "tw_profile_id"}
]
Response
{
"estimatedTime": 30000,
"loadTimeout": 60000
}
estimatedTime- Milliseconds until data ready (0 = already loaded)loadTimeout- Maximum wait time
Important Notes
- You cannot modify the report after confirmation
- Confirming does not itself consume a report credit — the credit gate is checked when you
first create the report (
POST /createreturns402if you have none, see below); the credit is actually deducted the first time you view the finished report (GET /report/{reportId}), transparently, with no separate confirmation step - Repeating
POST /create/{reportId}/confirmon a report you already confirmed returns409with"report profiles were already confirmed"— the earlier profile selection was already locked in and is left untouched - If
estimatedTime > 0, wait before fetching the report - Confirm requires a signed-in account: it returns
401for a guest session with no user ID, even though the earlier steps work for guests too
Step 5: Monitor Progress
Check Status
GET /check/{reportId}
{
"generated": true,
"ready": true,
"inProgress": false
}
GET /check/{reportId} returns 404 (not 403) when the caller does not own the report — this
avoids confirming that a given report ID exists to someone who isn't allowed to see it.
Real-time Updates (SSE)
Connect to SSE for live updates:
GET /sse/{reportId}
See Real-time Updates Guide for details.
Step 6: Get Report
Report page (slim — default)
GET /report/{reportId}
Returns ReportPage: per-source rows, previews, merged highlights rollup. Not the full monolithic per-profile payload (see /full below).
Full interest categories (lazy-loaded detail)
GET /report/{reportId}/interests
# Optional: one network only
GET /report/{reportId}/interests?source=ig
Full report shape (monolithic JSON)
GET /report/{reportId}/full
Returns the full ReportItem list per profile (and optional embedded summary). Prefer GET /report/{reportId} for the slim page and GET /report/{reportId}/summary for summary-only.
Report for Specific Source
GET /report/{reportId}/{source}
Sorting Options
GET /report/{reportId}?sortByRedFlags=true&limit=50
Additional Data Endpoints
Friends List (unified)
GET /report/{reportId}/friends?limit=20&offset=0
Friends List (per source)
GET /report/{reportId}/friends/{source}?limit=20&offset=0
Common Interests with Friend
GET /report/{reportId}/{source}/common/{friendId}
Interest Details
GET /report/{reportId}/{source}/{interestId}
Profiles by Interest
GET /report/{reportId}/{source}/{interestId}/profiles
Interest Changes Over Time
GET /report/{reportId}/{source}/diffs?date=2024-01&type=new
AI Summary
GET /report/{reportId}/summary
Error Handling
Repeat Confirm
{
"code": 409,
"message": "report profiles were already confirmed"
}
POST /create/{reportId}/confirm on a report you already confirmed returns 409. A separate
403 "report was already generated" can come from other endpoints in this flow (e.g.
GET /create/{reportId} once the report has moved past the search-and-select stage) — it means
the report can no longer be edited, distinct from the 409 above.
Report Limit Exceeded
{
"code": 402,
"message": "to continue please upgrade your subscription"
}
POST /create (not confirm) returns 402 when you have no remaining report credits. An
unauthenticated caller instead gets "You have reached search limit. Please Sign up to continue.".
Profile Not Found
{
"code": 404,
"message": "Profile not found"
}
The specified profile ID doesn't exist in the search results.
Best Practices
- Cache the token - Don't authenticate on every request
- Use SSE for real-time updates - More efficient than polling
- Handle partial results - Some profiles may fail to load
- Store report IDs - Reports can be retrieved later without re-creation