Creator Search API Documentation & Hosted MCP Server
Janney AI's 180M+ creator database as a REST API and a hosted, drop-in MCP server. Search creators, find lookalikes, extract available contact emails, and pull audience demographics — from your own code or straight inside an AI agent.
Included with Growth ($299/month), Scale ($599/month), and Custom plans. New accounts can try the API and the MCP server with their free signup credits before choosing a plan. Scale includes higher API and MCP rate limits. Create and manage keys in the app.
What it is
A REST API and MCP server for programmatic creator discovery across TikTok, Instagram, and YouTube.
What it returns
Creator profiles, lookalikes, available contact emails, audience demographics, and remaining API credits.
Who should use it
Teams building agency dashboards, CRMs, data pipelines, marketplaces, or AI agents around creator search.
Authentication
All requests go to the base URL https://backend.janney.ai and carry your API key. Send it as an x-api-key header, or as Authorization: Bearer <key>. Create a key on the API & MCP page in the app.
# header
curl https://backend.janney.ai/api/v1/credits -H "x-api-key: YOUR_API_KEY"
# bearer
curl https://backend.janney.ai/api/v1/credits -H "Authorization: Bearer YOUR_API_KEY"Requests without a valid key return 401. Accounts without the required plan return 403.
Send JSON with Content-Type: application/json. A body that is not a JSON object returns 400 with {"error": "..."}; HTTP errors share that shape.
Endpoints
Machine-readable spec: GET https://backend.janney.ai/api/v1/openapi.json (OpenAPI 3.1, no key required). Import it into Postman, an HTTP client, or your agent framework.
From search to contact
Call POST /api/v1/search to shortlist creators, then pass the selected handles to POST /api/v1/enrich for live profiles and available contact emails. Add audience to fields only when you need demographics. To find N new creators who each have an email, start a POST /api/v1/enrich/bulk job.
Use filters.platforms, filters.countries, filters.min_followers, and filters.max_followers for exact creator constraints. filters.min_engagement_rate is a percentage, so 3 means 3%. Inspect applied_filters in the response. Audience demographics are returned per creator through /audience, not used to filter search results.
/api/v1/searchSearch creators
Search the creator database (TikTok / Instagram / YouTube) by a natural-language query and/or structured filters. Results have no email address; pass selected handles to /enrich for a live profile and available contact email. email_status is this account's own extraction memory. There is no total-match count: the index cannot say how many creators match in total, so page with has_more and offset.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
query | string | optional | Natural-language description of the creators you want, e.g. "fitness creators in the US with 10k–100k followers". |
filters | object | optional | Exact creator filters: platforms (array), countries (ISO-2 array), min_followers, max_followers, min_engagement_rate (percentage), and niche_tags. Audience age, gender, and location are not search filters. |
limit | integer | optional | How many creators to return. 1–100, default 20. |
offset | integer | optional | Pagination offset. Default 0. |
sort_by | string | optional | Sort field (e.g. relevancy, number_of_followers, engagement_rate). |
Response
| Field | Type | Description |
|---|---|---|
results | Creator[] | Matching creators (see Creator object below). Emails are not included. |
count | integer | Number of creators returned in this response. |
has_more | boolean | Whether another page exists. Raise offset to fetch it. |
applied_filters | object | The constraints that actually took effect. Some arrive as prose inside query and are parsed, so this is how you check what the engine really filtered on. {} when it applied none. |
Request
curl -X POST https://backend.janney.ai/api/v1/search \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "fitness creators in the US", "limit": 10}'Example response
{
"count": 10,
"has_more": true,
"applied_filters": {},
"results": [
{
"platform": "instagram",
"username": "timmyunleashed",
"display_name": "Tim",
"followers": 17769,
"engagement_rate": 4.1,
"verified": false,
"country": "US",
"gender": "male",
"niche_tags": ["fitness", "wellness"],
"profile_url": "https://www.instagram.com/timmyunleashed/",
"bio": "Coach. Daily workouts.",
"email_status": null
}
]
}/api/v1/enrichEnrich selected creators
After /search, send the handles you selected to get their live profile cards and available contact emails in one call. Choose fields from profile, email, and audience; the default is profile + email. Profile cards are free up to 500 per account per 24 hours; after that, profile requests return 429, so request fields: ["email"] alone. Email and audience use their existing per-hit credit rates. An email bought by this account within 30 days comes back free, while a creator checked within 24 hours with no public email is answered from memory unless recheck is true. The cap is 50 creators for email alone, 25 when profile is included, or 10 when audience is included. Set an HTTP client timeout of at least 180 seconds: a cold Instagram profile can take about 30 seconds. For finding N new creators with emails, use /enrich/bulk instead.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
creators | {platform, username}[] | optional | Creators you already picked, in order. Or send platform + username for one creator. Maximum 50, reduced to 25 with profile or 10 with audience. |
platform | string | optional | Single-creator form, together with username. |
username | string | optional | Single-creator form, together with platform. |
fields | string[] | optional | Any non-empty selection of profile, email, audience. Default: profile + email. Add audience only when needed. |
recheck | boolean | optional | Default false. Look again after a no-email check in the last 24 hours instead of answering from memory. |
refresh | boolean | optional | Default false. For audience only, force a fresh compute instead of a cached result. |
Response
| Field | Type | Description |
|---|---|---|
results | EnrichResult[] | One row per distinct creator in the order asked. Requested fields appear on each row; an unreadable profile or unavailable audience gets a row-level error. |
requested | integer | Number of creators requested. |
found | integer | Number of rows with an email. |
charged | object | { email, audience, credits }: new emails billed, audience hits billed, and total credits charged. |
already_checked | integer | Present when non-zero: no-email results answered from this account's 24-hour memory. |
notice | string | Present with already_checked; explains what was skipped. |
Request
curl -X POST https://backend.janney.ai/api/v1/enrich \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"creators": [{"platform": "instagram", "username": "samplecreator"}]}'Example response
{
"requested": 1,
"found": 1,
"charged": { "email": 1, "audience": 0, "credits": 1 },
"results": [
{
"platform": "instagram",
"username": "samplecreator",
"profile": {
"platform": "instagram",
"username": "samplecreator",
"followers": 12000,
"engagement_rate": 3.4,
"bio": "Fitness creator"
},
"email": "[email protected]",
"email_confidence": "high"
}
]
}/api/v1/similarFind similar creators
Return lookalike creators similar to a given one. As with /search, email_status reflects this account's own extraction history, not whether an address exists.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | required | instagram | tiktok | youtube. |
username | string | required | The seed creator's handle. |
limit | integer | optional | 1–100, default 20. |
filters | object | optional | Optional structured filters to narrow the lookalikes. |
Response
| Field | Type | Description |
|---|---|---|
results | Creator[] | Similar creators (Creator object). Emails not included. |
count | integer | Number returned. |
has_more | boolean | Whether another page of lookalikes exists. |
note | string | Present when results is empty because the seed creator is not in the database. |
Request
curl -X POST https://backend.janney.ai/api/v1/similar \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"platform": "instagram", "username": "timmyunleashed", "limit": 10}'Example response
{
"count": 10,
"has_more": true,
"results": [
{
"platform": "tiktok",
"username": "flytyfitness",
"display_name": "Flyty Fitness",
"followers": 52140,
"engagement_rate": 3.8,
"verified": false,
"country": "US",
"gender": "male",
"niche_tags": ["fitness", "wellness"],
"profile_url": "https://www.tiktok.com/@flytyfitness",
"bio": "Fitness creator and coach.",
"email_status": null
}
]
}/api/v1/enrich/emailExtract available contact emails
The email-only form of /enrich for creators you already picked. Synchronous extraction from bios, external links, contact pages, and linktrees. Budget about a minute per 50 creators and set your HTTP client timeout to at least 180 seconds. To find N creators with emails, use /enrich/bulk instead; it does not tie up a connection. An address this account already bought in the last 30 days comes back free — charged says what was billed — so re-running a list is safe. A creator checked in the last 24 hours with no public email is answered from memory: instant, free, counted in already_checked with a plain-language notice; pass recheck: true to look again.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
creators | {platform, username}[] | required | Up to 200 creators to extract emails for. (Or send platform + username for a single creator.) |
recheck | boolean | optional | Default false. Look again at creators whose last check found no public email within 24 hours. |
Response
| Field | Type | Description |
|---|---|---|
results | object[] | Per creator: { platform, username, email (string | null), confidence (string | null), email_confidence (string | null) }. Both confidence fields have the same value. |
found | integer | Number of creators for which an email was found. |
charged | integer | Number of new emails billed on this call. Addresses this account bought in the last 30 days are free. |
requested | integer | Number of creators requested. |
already_checked | integer | Present when non-zero: creators answered from memory after a check found no public email within 24 hours. |
notice | string | When already_checked is present, explains what was skipped and how to force a fresh check. |
Request
curl -X POST https://backend.janney.ai/api/v1/enrich/email \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"creators": [{"platform": "instagram", "username": "timmyunleashed"}]}'Example response
{
"requested": 1,
"found": 1,
"charged": 1,
"results": [
{ "platform": "instagram", "username": "timmyunleashed", "email": "tim\u0040example.com", "confidence": "high", "email_confidence": "high" }
]
}/api/v1/enrich/bulkFind creators with emails
Start an asynchronous job that finds creators matching your description and returns only those with available contact emails. Starting a job is free. Poll its status_url about every 5 seconds; jobs usually take 1–4 minutes, or up to 15 minutes for a large target. A narrow requirement (few creators in the database post about it consistently) can take the full 30-minute budget, with a hard cap at 40 minutes, and still return few or none. found only moves when a creator passes the content check, so a long run at found 0 means the job is working; widen the requirement rather than retrying. The completed job is charged once, at 1 credit per creator returned.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
requirement | string | optional | Describe the creators you want. query is accepted as an alias. Provide this or filters. |
filters | object | optional | Structured filters, as in /search. Provide this or requirement. |
target | integer | optional | Desired number of creators with emails. 1–1000, default 50; the job may find fewer. |
exclude_usernames | string[] | optional | Handles already returned by a previous job, to exclude when requesting more. |
Response
| Field | Type | Description |
|---|---|---|
job_id | string | Job identifier to use when polling. |
status | string | pending or running. |
target | integer | Requested number of creators. |
status_url | string | Relative URL to GET with your API key about every 5 seconds. |
note | string | Polling and timing guidance. |
Request
curl -X POST https://backend.janney.ai/api/v1/enrich/bulk \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"requirement": "US fitness creators", "target": 50}'Example response
{
"job_id": "job-example",
"status": "pending",
"target": 50,
"status_url": "/api/v1/enrich/bulk/job-example",
"note": "Poll every 5 seconds."
}/api/v1/enrich/bulk/{job_id}Check a bulk email job
Poll about every 5 seconds. Status is pending, running, completed, failed, or unknown. While running, examined may show how many creators the job has checked, including those rejected by the content check. Polling is free; when the job completes, it is charged only once at 1 credit per creator with an email, even if you poll again.
Response
| Field | Type | Description |
|---|---|---|
job_id | string | The job you requested. |
status | string | pending | running | completed | failed | unknown. |
examined | integer | While running, creators checked so far, including those rejected. Present when reported by the upstream service. |
found | integer | Creators found so far, or the total when completed. |
target | integer | null | Requested number of creators. |
results | BulkResult[] | Only on completion: one row per creator with an email. See fields below. |
note | string | Polling guidance while the job runs. |
error | string | Reason when status is failed or unknown. |
Request
curl https://backend.janney.ai/api/v1/enrich/bulk/job-example \
-H "x-api-key: YOUR_API_KEY"Example response
{
"job_id": "job-example",
"status": "completed",
"found": 1,
"target": 50,
"results": [
{
"username": "samplecreator",
"platform": "instagram",
"display_name": "Sample Creator",
"followers": 12000,
"engagement_rate": 3.4,
"verified": false,
"country": "US",
"niche_tags": ["fitness"],
"profile_url": "https://www.instagram.com/samplecreator/",
"bio": "Fitness creator",
"email": "[email protected]",
"email_confidence": "high"
}
]
}/api/v1/audienceAudience demographics
The audience-only form of /enrich for a creator you already picked: age, gender, top countries and languages. Charged only on a hit; a creator with no audience data returns { error, platform, username } and costs nothing. These figures are estimates modelled from a sample of the creator's followers, not a census — age is the roughest of them and is best read as directional, while gender and country are firmer.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | required | instagram | tiktok | youtube. |
username | string | required | The creator's handle. |
refresh | boolean | optional | Force a fresh compute instead of a cached result. |
Response
| Field | Type | Description |
|---|---|---|
platform | string | Echoes the platform you asked about. |
username | string | Echoes the creator you asked about. |
audience_age | object | Percent by bracket: under_25, 25_34, 35_plus. |
audience_gender | object | Percent split, e.g. { female: 86, male: 14 }. |
audience_geo_countries | object[] | [{ code, pct }] — top countries by share. |
audience_languages | object[] | [{ lang, pct, region }] — top languages. |
Request
curl -X POST https://backend.janney.ai/api/v1/audience \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"platform": "instagram", "username": "timmyunleashed"}'Example response
{
"platform": "instagram",
"username": "timmyunleashed",
"audience_gender": { "female": 86, "male": 14 },
"audience_age": { "under_25": 18, "25_34": 45, "35_plus": 36 },
"audience_geo_countries": [
{ "code": "US", "pct": 59.0 },
{ "code": "PH", "pct": 6.9 },
{ "code": "GB", "pct": 4.9 }
],
"audience_languages": [
{ "lang": "en", "pct": 100.0, "region": "US/UK/Global" }
]
}/api/v1/creditsRemaining credits
Check how many API credits are left on your account. Also available at /api/v1/me. Free — never charged.
Response
| Field | Type | Description |
|---|---|---|
available_credit | number | Credits remaining this billing period. |
used_credit | number | Credits used. |
ledger_balance | number | Granted balance. |
Request
curl https://backend.janney.ai/api/v1/credits \
-H "x-api-key: YOUR_API_KEY"Example response
{ "available_credit": 882.9, "used_credit": 197.1, "ledger_balance": 1080 }The Creator object
Returned by /search and /similar. Both endpoints return the same Creator object. Contact emails are excluded; send selected handles to /enrich. The email_status field is this account's extraction memory, not a claim about whether the creator has an email.
| Field | Type | Description |
|---|---|---|
platform | string | instagram | tiktok | youtube. |
username | string | The creator's handle. |
display_name | string | Display name. |
followers | integer | Follower count. |
engagement_rate | number | Engagement rate (%). |
verified | boolean | Platform-verified badge. |
country | string | ISO-2 country code, where known. |
creator_city | string | null | Creator's city when the search index knows it; null for most rows. |
gender | string | Inferred gender, where known. |
niche_tags | string[] | Niche / category tags. |
profile_url | string | Canonical link to the creator's profile. |
bio | string | Profile bio text. |
email_status | string | null | This account's extraction memory: on_file = address bought within 30 days; no_email_24h = checked within a day and found none; null = never asked. This does not say whether the creator has an email. |
The EnrichResult row
Returned by /enrich in the order requested. Each row contains the fields you asked for. A creator whose profile cannot be read or whose audience data is unavailable gets a row-level error; the rest of the batch still returns.
| Field | Type | Description |
|---|---|---|
platform | string | Creator platform. |
username | string | Creator handle. |
profile | Profile | null | Live card when requested; null if it could not be read. |
profile_error | string | Why this creator's live card could not be read; the other rows still return. |
email | string | null | Available contact email when requested; null when none was found. |
email_confidence | string | null | Confidence in the extracted email, where known. |
already_checked | boolean | This creator's no-email result came from this account's 24-hour memory. |
audience | Audience | null | Demographics when requested; null if unavailable. |
audience_error | string | Why this creator's audience data was unavailable; the other rows still return. |
The Profile object
The live card inside an /enrich result when fields includes profile.
| Field | Type | Description |
|---|---|---|
platform | string | instagram | tiktok | youtube. |
username | string | The creator's handle. |
display_name | string | null | Display name. |
followers | integer | null | Live follower count. |
engagement_rate | number | null | Engagement percentage; 3.1 means 3.1%. |
verified | boolean | null | Platform-verified badge. |
country | string | null | ISO-2 country code, where known. |
bio | string | null | Profile bio. |
avatar_url | string | null | Profile image URL; it may expire, so fetch the card again rather than storing it. |
external_urls | array | Links from the profile, such as a site, linktree, or shop. |
top_hashtags | array | Hashtags from recent content. |
recent_posts | {title: string | null, url: string | null, views: integer | string | null}[] | Latest posts, newest first. Post cover images are omitted because their URLs expire. |
avg_views | integer | null | Average views over the recent posts sampled. |
avg_likes | integer | null | Average likes over the recent posts sampled. |
avg_comments | integer | null | Average comments over the recent posts sampled. |
post_count | integer | null | Number of recent posts sampled for the averages. |
video_count | integer | null | Lifetime video count, where reported. |
oldest_post_at | string | null | Date of the oldest sampled post, useful with post_count for posting frequency. |
total_views | integer | null | Total views, where reported. |
total_likes | integer | null | Total likes, where reported. |
The BulkResult object
Returned in /enrich/bulk/{job_id} when the job completes. Each creator has an available contact email.
| Field | Type | Description |
|---|---|---|
platform | string | instagram | tiktok | youtube. |
username | string | The creator's handle. |
display_name | string | Display name. |
followers | integer | Follower count. |
engagement_rate | number | Engagement rate (%). |
verified | boolean | Platform-verified badge. |
country | string | ISO-2 country code, where known. |
niche_tags | string[] | Niche / category tags. |
profile_url | string | Canonical link to the creator's profile. |
bio | string | Profile bio text. |
email | string | Available contact email. |
email_confidence | string | null | Confidence in the extracted email, where known. |
MCP server
The same data as a hosted, standards-compliant MCP server — drop it into any MCP client and your AI agent can call it directly. One config works everywhere; swap YOUR_API_KEY for a key from the app.
{
"mcpServers": {
"janney": {
"command": "npx",
"args": [
"mcp-remote",
"https://backend.janney.ai/mcp",
"--header",
"Authorization: Bearer YOUR_API_KEY"
]
}
}
}Install docs by client
search_creators find_similar_creators enrich_creators enrich_email bulk_enrich_start bulk_enrich_status creator_audience get_remaining_credits After search_creators, use enrich_creators to get live profile cards and contact emails for selected handles in one call (or add audience when needed). Free profile cards are limited to 500 per account per 24 hours; after that, profile requests return 429, so use fields: ["email"] alone. enrich_email is the email-only form; creator_audience is the audience-only form. Both enrich_creators and enrich_email accept recheck: true to look again after a no-email check within 24 hours.
Credits & rate limits
Your plan's credits are shared across the app, REST API, and MCP, not separate quotas. In the SaaS app, search, pagination, similar creators, and profile viewing are free; credits are spent only when a contact address is successfully found, or on metered API/MCP actions. API search costs 0.01 credit per creator returned; contact email extraction costs 1 credit per email found. Growth includes 900 monthly credits, enough for up to 90,000 API search results or 900 available contact emails before renewal. Check the balance anytime with GET /api/v1/credits (or the get_remaining_credits MCP tool).
Cost per call
/search · /similar0.01 / creator/enrichprofile free; email / audience as below/enrich/email1 / new email found/enrich/bulkfree to start; 1 / email found on completion/audience1 / creator/credits · /mefree
Rate limits (per key)
- search / similar 120 / min
- enrich / email / audience / bulk start 30 / min
- bulk status / credits / me 300 / min
Over the limit returns 429 with a Retry-After header.
If the shared credit balance is exhausted, API requests return 402 and in-app credit-gated actions return 401 until the plan renews or you upgrade/contact sales. Credits roll over while a subscription remains active and expire when it ends. Self-serve one-time credit packs are discontinued.
502 means an upstream enrichment service failed. It is safe to retry; nothing was charged.
Related developer and campaign resources
Use these pages to connect the API documentation with Janney AI's marketplace listings, SaaS workflow, Growth developer access, and free creator search positioning.
Get started
The API and hosted MCP are included with Growth ($299/month), Scale ($599/month), and Custom plans. Scale includes higher rate limits. Subscribe, then create your key on the API & MCP page in the app.
