Introduction
The People Search endpoint returns full person profiles matching a combination of filters. All filters are optional and combined with AND logic. Results are drawn from our cache-based search index. This endpoint never triggers a live fetch.
Every result is a complete profile, the same shape the Profile endpoint returns, so you do not need a second call to get the full data of a hit. Use the free People search count endpoint to check how many profiles match before you spend credits.
Coming from
POST /v2/search/persons? See Migrating people search from persons to people.
Authorization
apikey
string
required
Authorization: Bearer YOUR_API_KEY header.Request body
All filters are optional and combined with AND logic. Scalar filters live in the table below; the nested-object filters (followersCount, currentCompanyEmployeeCountRange, totalExperienceMonths, location, experience) are documented as expandable field items right after, and pagination (cursor, perPage) closes the section.
firstName
string
lastName
string
headline
string
email
string
isOpenToWork
boolean
isCurrentlyEmployed
boolean
isPremium
boolean
isVerified
boolean
currentPositionTitle
string | string[]
excludeCurrentPositionTitle
string | string[]
positionTitle
string | string[]
excludePositionTitle
string | string[]
currentCompanyName
string
excludeCurrentCompanyName
string
companyName
string | string[]
excludeCompanyName
string | string[]
currentCompanyId
string | string[]
com_...) of the current employerexcludeCurrentCompanyId
string | string[]
com_... id, or array of ids, to excludecompanyId
string | string[]
com_... id, or array of idsexcludeCompanyId
string | string[]
com_... id, or array of ids, to excludecurrentCompanyLinkedinId
string | string[]
excludeCurrentCompanyLinkedinId
string | string[]
companyLinkedinId
string | string[]
excludeCompanyLinkedinId
string | string[]
currentCompanyPublicId
string | string[]
excludeCurrentCompanyPublicId
string | string[]
companyPublicId
string | string[]
excludeCompanyPublicId
string | string[]
currentCompanyIndustry
string | string[]
companyIndustry
string | string[]
excludeCompanyIndustry
string | string[]
currentFunction
string | string[]
excludeCurrentFunction
string | string[]
currentSubFunction
string | string[]
excludeCurrentSubFunction
string | string[]
currentSeniority
string | string[]
excludeCurrentSeniority
string | string[]
skills
string | string[]
languages
string | string[]
excludeLanguages
string | string[]
keywords
string
changedJobsWithinDays
number
maxDataAgeDate
string
cursor
string
metadata.nextCursor; request the next pageperPage
number
25)Filter validation: filters are validated before the query runs. Unknown field names, blank values, values outside a closed list (
currentCompanyIndustry,currentFunction,currentSubFunction,currentSeniority,changedJobsWithinDays,location.countryCode),keywordswithout a single word and inconsistent ranges return HTTP422with the offending field, the reason and suggested values, and cost 0 credits. Unknown fields are rejected rather than ignored, because an ignored filter would return unfiltered results. Each list filter accepts at most 20 values. See Search filter validation.
Note: Title matching is token-based, not exact:
"CTO"also matches"Deputy CTO". Multiple titles are OR-matched, and exclusions always win over matches. ThepositionTitle,companyName,companyId,companyLinkedinId,companyPublicIdandcompanyIndustryfilters match current and past positions, while theircurrent...counterparts match the current position only.
Position taxonomy
currentFunction, currentSubFunction, currentSeniority and the experience filter match a closed taxonomy of professional functions. A value must come from the taxonomy: case and surrounding spaces are ignored, and any other value is rejected with HTTP 422 and the closest valid values, never silently ignored.
There are 32 functions, 386 sub-functions and 10 seniorities. The functions and seniorities are listed below; the full sub-function list is long, so read it from the available fields endpoint, which returns every accepted value for each filter, plus the function each sub-function belongs to.
Functions (32)
- Administrative
- Agriculture and Environment
- Construction and Trades
- Consulting and Advisory
- Customer Service
- Design
- Education
- Energy and Utilities
- Entertainment and Gaming
- Executive and Leadership
- Finance
- Hospitality and Tourism
- Human Resources
- Legal
- Marketing
- Media and Communications
- Medical and Health
- Nonprofit and Government
- Not Employed
- Operations
- Other
- Personal and Home Services
- Product
- Project and Program Management
- Public Safety and Security
- Real Estate
- Research and Science
- Retail and Consumer
- Sales
- Software
- Traditional Engineering
- Transportation and Logistics
Seniorities (10)
- CXO
- VP
- Director
- Head
- Manager
- Partner
- Owner / Founder
- Individual Contributor
- Intern
- Other
Skills, languages, keywords and job changes
These four filters read the whole profile rather than one position. They combine with every other filter, and each of them except excludeLanguages is a valid search on its own.
Skills
skills matches the skills listed on the profile, whatever position or school they come from. Matching ignores case and accents and compares whole skill names, never part of one: "Java" does not match a profile that only lists "JavaScript", and "Machine Learning" is matched as one value. A list is OR-matched: a person matches when they list at least one of the requested skills.
Languages
languages keeps people who speak at least one of the requested languages, and excludeLanguages removes people who speak any of the listed ones. Profiles that list no language are kept by excludeLanguages, which only refines a search: sent alone, it is rejected.
Send language names in English. Profiles store their languages in their own spelling (Français, Inglese, Deutsch), and the following names also match those spellings: Arabic, Bengali, Catalan, Chinese, Czech, Danish, Dutch, English, Finnish, French, German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Mandarin, Norwegian, Polish, Portuguese, Punjabi, Romanian, Russian, Spanish, Swedish, Tagalog, Thai, Turkish, Ukrainian, Urdu, Vietnamese. Any other value is accepted and matches its exact spelling only. Matching compares whole names: "French" does not match "French Creole". There is no proficiency level: any level matches.
Note: about one profile in six lists its languages, so a
languagesfilter leaves out every profile that lists none.
Keywords
keywords is one string searched across the whole profile: names, headline, summary, current and past job titles, companies, industries, skills, schools, degrees, certifications, languages and location. The value is split into words, case and accents are ignored, and every word must appear somewhere in the profile, in any field and in any order: "react paris" means react and paris. Words are matched whole: "react" does not match "reactive". Because the words may come from different fields, there is no exact-phrase match. A value with no word at all, such as "!!!", returns HTTP 422.
Recent job change
changedJobsWithinDays keeps people whose current position started within the last 30, 60, 90 or 120 days, boundary included, counted in UTC days. A profile with no current position, or whose current position has no start date, does not match, and a start date in the future never matches. Any other value returns HTTP 422 with the accepted ones.
curl -X POST https://api.reversecontact.com/v2/search/people \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"currentFunction": "Software",
"skills": ["Python", "Machine Learning"],
"languages": "German",
"keywords": "fintech",
"changedJobsWithinDays": 90,
"location": { "countryCode": "DE" },
"perPage": 25
}'
Tip: on the largest countries, a lone
skillsorlanguagesfilter has to scan a very large set of profiles and can be slow. Pair it with a title, a function or a company to keep the search fast.
Pagination and credits
People search uses cursor pagination. Each response returns up to perPage profiles (1 to 100, default 25) and a metadata.nextCursor value. Pass that value back as cursor in the next request to get the following page; nextCursor is null on the last page. The cursor is opaque: send it back unchanged, without parsing or altering it. There is no page parameter.
A nextCursor has no hard expiry. The result list behind it is cached for 10 minutes. If you use a cursor after that, the search is re-run with the same filters and you get the next page from the refreshed list. If the data changed in the meantime, that page can contain a profile you already received or skip one. For a consistent result set, fetch each page within 10 minutes of the previous one.
An invalid or expired cursor returns HTTP 400 with the message Invalid or expired cursor. This happens when a filter is changed between two pages (keep the request body identical and only add the cursor), or when the cursor is malformed (truncated or altered).
perPage above 100 returns HTTP 422 with error.code PAGINATION_LIMIT_EXCEEDED, and the error.details object identifies the field and maximum, for example { "field": "perPage", "max": 100 }.
People search costs 1 credit per profile delivered. Compliance-blocked profiles are removed before the response and are not billed. A page that returns 25 profiles costs 25 credits, and a page that returns no profile costs 0 credits. Check the size of a query first with the free People search count endpoint, and lower perPage to control how many credits a single request can spend.
Response structure
Note: This endpoint uses a nested envelope. The top-level V2
datafield wraps an inner search payload that contains the actual results array (data.data) and the pagination info (data.metadata). See the example response for the exact shape.
success
boolean
true if the request was processed successfullyerror
null
null on success