What is a people search API?
A people search API lets you query a people dataset by criteria such as job title, company, location, keywords, or other filters and receive matching person records.
Submit a natural-language description of who you are looking for, optionally narrowed by structured custom_filters. The request is queued asynchronously and returns a request_id; poll the status endpoint for results. Completed searches paginate three ways: by cursor (recommended), by request_id + offset, or by repeating the same query with an offset.
Manual credentials take precedence over your account key.
The People Search API finds matching people from a natural-language query and structured filters, then returns profile candidates you can qualify, enrich, or route into sales and data workflows.
query and/or structured custom_filters - at least one is required (unless paginating with cursor or request_id). With no query, the search runs purely on custom_filters.insights.why_matched contains concise evidence chips showing the criterion, evidence type, confidence, and a safe short matched phrase when available. Most useful when a query is supplied.score (integer 1-5) ranking how well each profile matches the query. Most useful when a query is supplied.locations, titles, companies, universities, degrees, specialization_categories, plus the array filters industries (industry names, lowercase; LinkedIn taxonomy synonyms accepted, e.g. ["fintech","financial services"]), keywords (free-text terms that must each appear in the profile text/skills/interests; multiple keywords are ANDed), and languages (spoken languages, 2-3 common forms each, e.g. ["spanish","espanol"] or ["chinese","mandarin","中文"]). Supports array filters (any-of), numeric ranges, booleans, and exact-match values.next_cursor. Submitting it fetches the next page.offset + limit may not exceed 10000.offset/limit to page through results, or poll for completion with a GET (polling never consumes credits).This endpoint is asynchronous. A successful submit returns a request_id while the job runs in the background. Poll the same path with a GET request - same authentication headers - passing the request_id as a
query parameter:
Each poll returns the job's current status; once it is completed the payload carries the result shown under Responses. Polling an
unknown or expired request_id returns 404 request_not_found.
| Status | Meaning |
|---|---|
| queued · processing · pending | The job is still running - keep polling. |
| completed | The job finished; the payload carries the result and completed: true. |
| failed | Terminal - the job could not complete; the error field explains why. |
Poll every few seconds at first, backing off for long-running jobs. Polling is free - status checks never burn credits.
callback_url parameter and the completed payload is POSTed to your endpoint
when the job finishes - no polling required. Delivery is retried up to 5 times with exponential backoff (1s,
5s, 15s, 1m, 5m) and a 30-second timeout per attempt; respond with a 2xx status to acknowledge receipt.A completed search returns one page of results plus the cursor and counters you need to walk the rest. Each search request (a POST) that returns results is billed for the results on that page; only polling an in-flight search with a GET + request_id is free. offset + limit may not exceed 10000.
Every completed response carries these fields - read them to decide whether to fetch another page:
| Field | What it tells you |
|---|---|
| has_more | true means more results are available beyond this page - fetch the next page. false means you have reached the end; stop. |
| next_cursor | An opaque token for the next page. Present only when has_more is true (omitted on the last page). Pass it back as the cursor parameter - it already encodes the next offset, limit and request_id. |
| total_estimate | Approximate total number of matches for the query. Use it to size a progress bar or decide how many pages to pull; treat it as an estimate, not an exact count. |
| offset / limit | The slice this response represents: results offset through offset + limit - 1. |
| Method | How |
|---|---|
| Cursor (recommended) | Take next_cursor from the response and send it as cursor on the next request (no other params needed). Repeat until has_more is false. |
| request_id + offset | Re-send the original request_id with an increasing offset (e.g. offset: 25, then 50, using your chosen limit). |
| Repeat the query + offset | Re-submit the same query (and identical custom_filters) with a higher offset. The service matches it to the existing search session. Prefer cursor or request_id when you have them - they are unambiguous. |
Pagination is forward-only and consistent within a search session: results keep their position, so paging never skips or duplicates a person. Each page you request with a POST is charged for the results it returns; checking status with a GET and a request_id is always free, so you can re-read data you have already retrieved without being charged again.
Credits are charged based on the matched configuration. The listed cost is the per-result unit price.
| Feature | Credits | Notes |
|---|---|---|
| Person Search | 1 | per result returned |
| Smart Ranking | 1 | profile_scoring: true |
| Candidate Insights | 1 | insights: true |
| Filter | 1 | custom_filters: true |
| Enrich Emails | 6 | show_emails: true (per result; or require_emails) |
| Enrich Phones | 6 | show_phone_numbers: true (per result; or require_phone_numbers) |
A successful response wraps the payload in the { success, data, timestamp } envelope (also shown live in the panel on the right):
{
"success": true,
"data": {
"request_id": "abc12345_1737123456_1234",
"status": "completed",
"completed": true,
"results": [
{
"profile_id": "li_johnsmith",
"displayname": "John Smith",
"firstname": "John",
"middlename": "A",
"lastname": "Smith",
"gender": "male",
"headline": "Senior Sales Manager at Tech Corp",
"bio": "Enterprise sales leader with 15 years closing Fortune 500 accounts.",
"location": "San Francisco, CA",
"altemails": [
"[email protected]",
"[email protected]"
],
"fullphone": [
{
"fullphone": "+1-555-123-4567",
"phone_type": "mobile"
}
],
"social_profiles": {
"linkedin": {
"url": "https://linkedin.com/in/johnsmith",
"username": "johnsmith",
"followers": 1200,
"connections": 500
}
},
"organizations": [
{
"name": "Tech Corp",
"company_domain": "techcorp.com",
"title": "Senior Sales Manager",
"startDate": "2020-03",
"endDate": null
}
],
"schools_info": [
{
"name": "University of California, Berkeley",
"degree": "BS",
"specialization_category": "Business",
"startDate": "2001",
"endDate": "2005"
}
],
"skills": [
"enterprise sales",
"negotiation"
],
"languages": [
"english"
],
"estimated_age": 42,
"score": 5,
"insights": {
"overall_summary": "Strong match: senior sales leadership at a large enterprise in the target metro.",
"why_matched": [
{
"criterion": "Sales managers at Fortune 500 companies",
"evidence_type": "work_experience",
"confidence": "strong",
"display_text": "Current role shows senior sales management at Tech Corp.",
"matched_phrase": "Senior Sales Manager at Tech Corp"
},
{
"criterion": "San Francisco",
"evidence_type": "location",
"confidence": "strong",
"display_text": "Profile location is in the requested metro."
}
],
"query_insights": [
{
"subquery_idx": 0,
"subquery": "Sales managers at Fortune 500 companies",
"priority": "Essential",
"match_level": "Meets Expectations",
"short_rationale": "Senior Sales Manager at a Fortune 500 company.",
"rationale": "Currently Senior Sales Manager at Tech Corp, a Fortune 500 enterprise.",
"short_quotes": [
"Senior Sales Manager at Tech Corp"
]
}
]
}
}
],
"offset": 0,
"limit": 25,
"total_estimate": 500,
"has_more": true,
"next_cursor": "eyJvIjoyNSwiciI6ImFiYzEyMzQ1…",
"credits_charged": 125
},
"timestamp": "2026-01-01T00:00:00"
}