Skip to main content

Endpoint essentials

Use the Person Search API to find people by name, title, company, location, and other fields. This page shows:
  • Your first search.
  • The shape of the response.
  • How to combine filters.
  • Example requests and recipes that you can copy and change.
For the operator list, the field catalog, and the validation rules, see Search reference. Send every request to this endpoint:
In each example, replace YOUR_API_KEY with your API key. Every request must include the x-api-version: 2025-11-01 header.
Pricing: The base price is 0.03 credits per result. Each premium group that you filter on or receive adds a per-result charge:
  • Experience, education, and skills: 0.1.
  • Certifications, honors, professional network signals, languages, and summary: 0.2.
  • Dev platform profile filters: 0.8 (profile) or 2.5 (repositories).
  • Research profiles (enabled on request): 0.4.
A filter on a premium group is one charge. The same group in the response is a separate charge. Sorting is free. A request with no fields returns experience and education, so it costs 0.23 per result on the standard plan. For the full table, see Premium fields in search. For your own prices, open the Pricing tab in the dashboard or call /account/endpoints.
For the full table of filters.field values that you can filter on, see Searchable fields in the search reference. The table groups the fields by family. The reference also shows a one-line way to get the live list from the API.

Examples

See requests for employer and title, geo radius, country, and post-processing exclusions.

Pagination and sorting

Get the next page with a cursor. Sort the results to keep a stable order.

Reference

Look up operators, searchable fields, response fields, preview mode, and errors.

Your first search: find a person by name

The simplest search finds a person by their exact name. Send one filter with the = operator.
This example shows only part of the response.

Understanding the response

Every search response has three fields:
  • profiles: An array of matching people. Each profile contains identity fields, education, profile handles, and contact availability flags for the fields that you requested.
  • total_count: The number of people in the full database that match your filters. In this example, 8 people have the name “Abhilash Chowdhary”.
  • next_cursor: A pagination token. To get the next page of results, send this token in the next request. A null value means that there are no more pages.

Combine filters with and

Most searches need more than one condition. To require all of the conditions, put them in a group with op: "and". This search finds co-founders in San Francisco. The (.) operator matches when every word in the value appears, in any order. It does not match the whole string exactly. On some fields (.) also matches close misspellings. When you need the exact words, use [.] or in instead. See Choose a text operator.
This example shows only part of the response.
Compare this request with the first example. The first example sends one condition object in filters. This example sends a group with op: "and" and a conditions array. A profile is in the results only when every condition matches. For more filter patterns, such as employer and title, geo radius, and exclusions, see the example requests below. To get every page of a large result set, see Pagination and sorting.

Read normalized titles and education details

Each profile also includes a normalized title classification and structured education data. The education data includes the school location and an institution logo that Crustdata hosts. Use fields to request the sections that you need. To get one person, filter by crustdata_person_id.
You can filter on basic_profile.normalized_title and education.schools.location, but you cannot sort on them.You can filter and sort on professional_network.followers and professional_network.connections, but the search response does not include them. Use them to narrow or rank the results, not to read the counts.The response includes the school description and institute_logo_permalink fields for display only.

Example requests

These examples show common filter patterns for Person Search. Each example is a full, tested request to POST /person/search. You can copy a request and change it. Click a row to expand it.
Find people whose current title is exactly “Chief Executive Officer”:
= and in match the full title string exactly. For example, "Chief Information Security Officer" does not match people with the title “Deputy Chief Information Security Officer” or “SVP and CISO”. Titles usually need a substring or word match. For that, use the (.) operator, as in the next example.
Find people whose headline contains “founder”. This match ignores case:
Find people with more than 10 years of experience:
Find people with more than 500 connections who recently changed jobs:
Find people in a region, but exclude some employers and titles:
Find senior people (VP, Director, or CXO) who have 10 or more years of experience and work at a company with fewer than 1,000 employees:
Find people who started a role at a public company in 2023 or later and have 15 or fewer years of experience:
Find Stanford alumni who have a machine learning skill and a degree that is not “Bachelor”:

Semantic search (natural language)

You can send a natural-language query in search.query instead of building filters by hand. The API ranks people by the meaning of their full profile. search.mode sets how the matching works: The API reranks the top results, called the head. Each profile in the head has a relevance fit tier: strong, possible, or weak. Profiles after the head have fit: null. The response uses the standard Person Search shape, plus the fit and total_count_relation fields:
Response shape
Semantic search is in beta. Do not send sorts, because the results are already in relevance order. A query never removes a profile that your filters selected. In the default mode: "managed", a query can add profiles, so total_count can be much larger than the count for your filters alone. For the recall modes (managed and exact) and the full behavior, see the Person Semantic Search guide.
hybrid is the default mode. Describe the people that you want in plain language. hybrid combines keyword and semantic matching, which gives the best general-purpose recall.
Use lexical when exact terms, acronyms, tools, or names are the most important. This mode uses keyword matching only, with no vector similarity.
For a precise keyword search, set search.query_syntax: "boolean". The API then reads the query as a boolean expression:
  • A space means AND.
  • | means OR.
  • + requires a term.
  • - excludes a term.
  • "…" matches an exact phrase.
  • * matches a prefix.
  • () groups operators.
The API uses query_syntax only when you also send search.mode: "lexical" and the top-level recall mode: "exact".
For the full operator reference, see the Person Semantic Search guide.
Use semantic to match the meaning of a query, even when profiles use different words. This mode uses vector similarity only.
With the top-level mode: "exact", every result must match your filters. The query then ranks the profiles inside that set.

More recipes

Each recipe below is a full walkthrough with a tested request. Expand a recipe to see the pattern, the response, and how the operators work.
Sales and recruiting teams use this pattern the most. It finds people with a specific title at a specific company. This search finds VPs, Directors, and Heads of department at Retool.
This example shows only part of the response.

How the operators work

This search uses two operators:
  • in on experience.employment_details.company_name checks if the person worked at any of the listed companies, now or in the past. Send an array, even for one company. To search only current employers, use experience.employment_details.current.company_name.
  • (.) on experience.employment_details.current.title matches when every word in the value appears in the current title, in any order. The or group holds one (.) condition for each title, so a profile matches when any one of them matches. To also match past titles, use experience.employment_details.title.
The experience.employment_details.company_name field includes all employers, current and past. A result can have a current role at a different company. That person worked at your target company in the past.
A | in a (.) value does not mean OR. The API reads "VP|Director" the same as "VP Director", so a title must contain both words. To match any one of several titles, put one (.) condition for each title in an or group, as in this example.
If you know the profile URL of a company but not its exact name, filter on the employer profile URL. Two companies can have the same name, but a profile URL points to one company. This is the most reliable way to find people at one specific company.To find people who work there now, use the current-employer field:
This example shows only part of the response.
Send the company page URL, for example https://www.linkedin.com/company/stripe. Search also accepts the URL with a trailing slash (.../stripe/), with no scheme (linkedin.com/company/stripe), or with no www.. Each form returns the same profiles.

Current, former, or either

  • Current employees: experience.employment_details.current.company_professional_network_profile_url
  • Former employees: experience.employment_details.past.company_professional_network_profile_url
  • Anyone who ever worked there: combine both fields in an or group.
To search several companies in one request, use the in operator with an array of profile URLs.
You cannot filter on the bare experience.employment_details.company_professional_network_profile_url path (all employers). Use the current. or past. path above. The API also accepts the alias ...company_linkedin_profile_url, which points to the same data.
These fields take the company page of the employer. A school page, a person profile, or a bare slug returns 400, because Crustdata stores no employer under these URLs. For the URL shapes that search accepts, see Employer profile URL values.
Every employment object has a company_status field. It shows the lifecycle state of the employer in the Crustdata entity graph. It has three values:
  • active: The employer is a live company record.
  • deleted: Crustdata retired the company record.
  • null: Crustdata never resolved the employer to a company record. The role has only the free-text company name.
Filter on company_status when a later step needs a real company behind the role. For example, use it before you enrich the employer or send the person to an account owner. This search finds directors at Stripe. It keeps only roles whose employer is a live record.
To check a former employer, change current. to past.. To match any role that the person held, remove the prefix: experience.employment_details.company_status.
A profile matches when any one of its roles meets the condition. So this filter does not make sure that every role on a returned profile is active. The two profiles above keep all of their current roles, including roles at other companies. Read company_status on the role that you use. Do not assume its value because the profile matched.
To get everyone at a company except some roles, use the not_in operator to exclude titles.This search finds people at OpenAI or Retool, but excludes interns and students.
The not_in operator removes every profile where one of the listed values appears in the title history. Use it to clean up results in recruiting or sales workflows.
The geo_distance filter finds people within a specific distance of a city. Use it for territory-based sales or local recruiting.This search finds people within 10 miles of San Francisco whose current title contains “CTO” or “Chief Technology Officer”.
This example shows only part of the response.

How geo_distance works

The geo_distance filter uses the professional_network.location.raw field. The value is an object that sets the center point in one of two ways:
  • A location string. The server geocodes it.
  • An explicit lat_lng pair. This skips geocoding.
If you send both, the API uses lat_lng.

Search by explicit coordinates

Use lat_lng when you already have coordinates, for example from a map picker. You can also use it to skip the geocoding step. The example below finds people within 5 km of latitude 37.7749, longitude -122.4194 (downtown San Francisco).
The geo_exclude filter is the inverse of geo_distance. It removes people inside the radius and keeps everyone else. Use it to remove a metro area that you already cover. You can also use it to find candidates outside a relocation zone.This search finds engineers who are not within 50 km of San Francisco.
geo_exclude takes the same value object as geo_distance: location or lat_lng, a required distance, and an optional unit. So you can also exclude a radius around explicit coordinates.
The geo_polygon filter finds people located inside a polygon you describe with coordinates. Reach for it when a circle is the wrong shape for the area you care about, such as a sales territory or a commute zone traced on a map.This search finds engineers located inside a box over the San Francisco peninsula.
The value is an object with a single points key: a list of [lat, lng] pairs, at least 3 distinct points and at most 1,000. The polygon closes itself, so you do not need to repeat the first point. Coordinates are used as given and are not geocoded. See the geo_polygon reference for the value-object table and the 400 cases.
Use (!) to remove profiles whose value contains a specific phrase. not_in needs exact values. Use (!) when you need a substring exclusion instead.This search finds VP-level people at Retool. Then it removes anyone whose headline contains “Investor” or “Advisor”.
(!) matches a multi-word value as a literal phrase. (!) "New York" excludes only profiles that contain the literal phrase "New York". It does not exclude "New Yorker". To exclude each word on its own, send a separate (!) condition for each word in an and group, as in the example above.
For a wider geographic search, filter by country.
basic_profile.location.country uses full country names, such as "United States" or "India".
This search returns all people in the United States. More than 125M profiles match, so combine this filter with a title or employer filter to narrow the results.
Use company_headquarters_country to filter by the headquarters country of a person’s current or past employer.
company_headquarters_country accepts a full country name, such as United States, or an ISO 3166-1 alpha-3 code, such as USA. Both forms return the same people on the current, past, and all-roles headquarters country fields. The response returns the full country name. basic_profile.location.country accepts full names only.
This search finds founders or co-founders whose current employer has its headquarters in the United States. Each person also worked at an employer with headquarters in India in the past.
Use post_processing to remove known profiles from the results. For example, when you run a search again, use it to skip people that you already contacted.
You can exclude by name, by profile URL, or both.
Person Search returns stable logo permalinks that Crustdata hosts. Employers have company_profile_picture_permalink, and schools have institute_logo_permalink. You can show a profile card with these links, and you do not have to find the image URLs yourself. Request the experience and education sections for the person that you want.
The response includes company_profile_picture_permalink and institute_logo_permalink for display only. You cannot search on these fields.
If you know the website domain of a company but not its exact display name, filter on the employer domain. To find people who work there now, use the current-employer field.
This example shows only part of the response. The response has the full website URL of the employer in company_website. The company_website_domain paths are filter names only. They do not appear in search responses.
To search several companies in one request, use the in operator with an array of domains. Pick the field for the people that you want:
  • Current employees: the current. field above.
  • Former employees: experience.employment_details.past.company_website_domain.
  • Anyone who ever worked there: the all-roles field experience.employment_details.company_website_domain.
Combine the recently_changed_jobs flag with a current-employer filter. This limits the job-change signal to one target company. It is a good start for sales and recruiting outreach.
This example shows only part of the response.
recently_changed_jobs is a boolean. Combine it with a current. employer or title filter to limit the signal to the people that you want. You can filter and sort on it, but the response does not include it.The flag marks a past role that ended within 90 days of the last index rebuild. It does not mark a new role that started. To find people who recently started a role, filter experience.employment_details.current.start_date on a date range.
To find only individual contributors, use not_in on the all-roles paths: experience.employment_details.seniority_level and experience.employment_details.title. On these paths, not_in removes anyone who ever held that seniority or title, in any role. It does not check only the current role.
This search keeps people whose current title contains “engineer”. It excludes anyone who was ever a VP, Director, or CXO, or who held a founder or CEO-level title. The exclusions are on the all-roles paths, so one past executive role removes a profile.
Use not_in on the all-roles path experience.employment_details.company_name to remove anyone who ever worked at a named company, now or in the past. This is the most direct way to remove competitor alumni from a candidate or prospect list.
The all-roles company_name path covers current and past employers. So this search excludes a profile if Google or Meta appears anywhere in the work history. To match one exact company, use the company profile URL paths (...company_professional_network_profile_url), not names.
Combine filters to find founders for an investor pipeline. This search uses four filters:
  • A founder or CEO title.
  • A target school.
  • A recent start date for the current role. This is a proxy for a recently founded company.
  • A country.
Each filter makes the result set smaller.
This example shows only part of the response. basic_profile.location.country uses full country names. current.start_date accepts ISO date strings with the => (greater than or equal) operator.
A cross-border mover is a person who moved from an employer in one country to an employer in another country. To find cross-border movers, filter on the headquarters country of the past and current employers. For example, find engineers who worked at companies with headquarters in India and now work at companies with headquarters in the US. The headquarters country fields accept an ISO 3166-1 alpha-3 code, such as IND, or a full country name, such as India.
This example shows only part of the response. The location of the person and the headquarters country of the employer are independent. This person is in the Netherlands, but the employers have headquarters in the US and India.
For the widest geographic search, filter on basic_profile.location.continent. It takes a full continent name, such as "Europe", "Asia", or "North America".
This search returns founders anywhere in Europe. At the time of writing, total_count was 1,055,157. To narrow a large result set, combine the continent filter with a title, employer, or country filter. You can filter on basic_profile.location.continent, but you cannot sort on it.
To find people who worked at both of two named companies, use one company as the current employer and the other as a past employer. Use a different path for each company: experience.employment_details.current.company_name and experience.employment_details.past.company_name.
This example shows only part of the response.
This pattern works because the search matches each company against a different employment slot: current. or past.. Two = conditions with two different company names on the same all-roles path (experience.employment_details.company_name) return zero results. One employment record cannot equal both names.
Filter on experience.employment_details.current.business_email_verified to keep only profiles that have a verified business email on the current role. Use it when you plan to enrich the profiles and contact people by email.
This example shows only part of the response. You can filter on business_email_verified on the current, past, and all-roles paths. The response also includes it in the current role, as in the example above. The response does not include the email address. To get the email address, use Contact Enrich.
Add a sorts array to sort the results. This search finds everyone who worked at Retool, now or in the past, and sorts them by professional network followers, highest first. In fields, request the fields that you want to read with the sort key.
This example shows only part of the response.
You can filter and sort on professional_network.followers, but the results do not include it. The sort orders profiles by follower count, but it does not show the count. When you paginate, always send a sorts array so that the order stays the same across pages. See Pagination and sorting.
Filter on research_profiles.h_index.all to keep people whose matched academic author profile has an h-index above 100, sort by lifetime citations, and read the name and citation count back in fields. The group is enabled per account. Without the grant, the request returns 403 with Access denied to fields: research_profiles.
research_profiles is an array because a person can hold more than one author profile. A filter matches when any of them matches. Search returns a smaller copy of each profile than enrich does. See Research profiles for the filterable and sortable paths, and Person Enrich for the full article and co-author lists.
Preview mode returns smaller results. Use it to check a filter and read total_count before you run a full search. To use it, set preview: true with your normal filters.
Preview is a premium feature. To turn it on for your account, contact gtm@crustdata.co. If your account does not have preview, the API returns 403 permission_error. For the full error, see Preview mode in the search reference.
This example shows only part of the response.
A preview response has the same top-level shape as a normal search: profiles, next_cursor, and total_count. But each profile has fewer fields. For details, see Preview mode in the search reference.

What to do next

  • To try more filter patterns, see the example requests above. They cover employer and title, geo radius, and exclusion patterns.
  • To get every matching profile in a stable order, see Pagination and sorting.
  • To look up operators, searchable fields, response fields, request parameters, and errors, see Search reference.
  • To get the full cached profile for a profile URL from search, use Person Enrich.
  • To find the exact indexed values for a filter before you build it, use Person Autocomplete.
  • For the full schema, see the OpenAPI spec.