Skip to main content
The Person Search API lets you find professionals by name, title, company, location, and more. This page walks you through the API step by step, starting with the simplest possible request and building up to advanced queries. Every request goes to the same endpoint:
POST https://api.crustdata.com/person/search
Replace YOUR_API_KEY in each example with your actual API key. All requests require the x-api-version: 2025-11-01 header.

Your first search: find a person by name

The simplest search finds a person by their exact name. You pass a single filter with the = operator.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "basic_profile.name",
      "type": "=",
      "value": "Abhilash Chowdhary"
    },
    "limit": 1
  }'
Response trimmed for clarity.

Understanding the response

Every search response has three fields:
  • profiles — an array of matching people. Each profile contains identity, employment, education, skills, and contact data.
  • total_count — how many people match your filters across the full database. Here, 8 people named “Abhilash Chowdhary” exist.
  • next_cursor — a pagination token. Pass it in the next request to get the next page of results. null means there are no more pages.

Combine filters with and

Real searches need more than one criterion. Wrap multiple conditions inside an op: "and" group to require all of them. This search finds Co-Founders located in San Francisco. The (.) operator does a regex/contains match instead of an exact match.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        {
          "field": "experience.employment_details.title",
          "type": "(.)",
          "value": "Co-Founder"
        },
        {
          "field": "basic_profile.location.full_location",
          "type": "(.)",
          "value": "San Francisco"
        }
      ]
    },
    "limit": 2
  }'
Response trimmed for clarity.
The key difference from the first example: instead of a single filters object, you now have a group with op: "and" and a conditions array. Every condition must match for a profile to be included.

Search by employer and title

This is the most common pattern for sales and recruiting: find people with a specific title at a specific company. This search finds VPs, Directors, and Heads of department at Retool.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        {
          "field": "experience.employment_details.company_name",
          "type": "in",
          "value": ["Retool"]
        },
        {
          "field": "experience.employment_details.title",
          "type": "(.)",
          "value": "VP|Director|Head of"
        }
      ]
    },
    "limit": 1
  }'
Response trimmed for clarity.

How the operators work

There are two different operators at play here:
  • in on experience.employment_details.company_name checks if the person has worked at any of the listed companies (current or past). Pass an array even for a single company. To search only current employers, use experience.employment_details.current.company_name instead.
  • (.) on experience.employment_details.title does a regex match. The pipe | means “or”, so VP|Director|Head of matches any title containing “VP”, “Director”, or “Head of”. To search only current titles, use experience.employment_details.current.title instead.
The experience.employment_details.company_name field includes all employers (current and past). If you see someone whose current role is at a different company, it means they previously worked at your target company.

Exclude specific titles

Sometimes you want everyone at a company except certain roles. Use the not_in operator to exclude titles. This search finds people at OpenAI or Retool but excludes interns and students.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        {
          "field": "experience.employment_details.company_name",
          "type": "in",
          "value": ["OpenAI", "Retool"]
        },
        {
          "field": "experience.employment_details.title",
          "type": "not_in",
          "value": ["Intern", "Student"]
        }
      ]
    },
    "limit": 2
  }'
The not_in operator removes any profile where one of the listed values appears in their title history. This is useful for cleaning up results in recruiting or sales workflows.

Search within a geographic radius

The geo_distance filter finds people within a specific distance of a city. This is powerful for territory-based sales or local recruiting. This search finds CTOs within 10 miles of San Francisco.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        {
          "field": "professional_network.location.raw",
          "type": "geo_distance",
          "value": {
            "location": "San Francisco",
            "distance": 10,
            "unit": "mi"
          }
        },
        {
          "field": "experience.employment_details.current.title",
          "type": "(.)",
          "value": "CTO|Chief Technology"
        }
      ]
    },
    "limit": 1
  }'
Response trimmed for clarity.

How geo_distance works

The geo_distance filter uses the professional_network.location.raw field. The value is an object with three fields:
FieldRequiredDescription
locationYesCity name or region (e.g., “San Francisco”, “London”, “New York”)
distanceYesRadius from the center point
unitNoDistance unit: mi, km, m, ft. Defaults to km

Search by country

For broader geographic targeting, filter by country directly.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "basic_profile.location.country",
      "type": "=",
      "value": "United States"
    },
    "limit": 2
  }'
This returns all people located in the United States. With 125M+ matching profiles, you will want to combine this with title or employer filters to narrow results.

Paginate through results

When your search matches more profiles than your limit, use cursor-based pagination to walk through all pages. First page: send your normal search request.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "experience.employment_details.company_name",
      "type": "in",
      "value": ["Retool"]
    },
    "limit": 100
  }'
Next page: take the next_cursor value from the response and pass it in your next request. Keep the same filters and limit.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "experience.employment_details.company_name",
      "type": "in",
      "value": ["Retool"]
    },
    "limit": 100,
    "cursor": "PASTE_NEXT_CURSOR_VALUE_HERE"
  }'
Continue until next_cursor is null, which means you have reached the last page.
Always include sorts when paginating to ensure stable ordering across pages.

Sort results

Use the sorts parameter to order results by a specific field. This is important for stable pagination.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "experience.employment_details.current.title",
      "type": "=",
      "value": "CEO"
    },
    "sorts": [{"field": "professional_network.connections", "order": "desc"}],
    "limit": 5,
    "fields": ["basic_profile.name", "professional_network.connections"]
  }'
Valid sortable fields include: crustdata_person_id, basic_profile.name, professional_network.connections, experience.employment_details.start_date, experience.employment_details.company_id, metadata.updated_at.

Exclude specific people from results

Use post_processing to remove known profiles from results. This is useful when re-running searches and you want to skip people you have already contacted.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "experience.employment_details.title",
      "type": "(.)",
      "value": "Founder"
    },
    "limit": 5,
    "post_processing": {
      "exclude_names": ["Ali Kashani"],
      "exclude_profiles": ["https://www.linkedin.com/in/alikashani"]
    }
  }'
You can exclude by name, by LinkedIn URL, or both.

Preview mode

Use preview: true to get lightweight results before committing credits. Preview responses have the same structure but may return fewer fields.
curl --request POST \
  --url https://api.crustdata.com/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "field": "experience.employment_details.title",
      "type": "(.)",
      "value": "Founder"
    },
    "preview": true,
    "limit": 2
  }'

Filter operator reference

OperatorMeaningExample use
=Exact matchbasic_profile.name = “David Hsu”
!=Not equalExclude a specific country
> / <Greater/less thanNumeric comparisons
inValue is in listexperience.employment_details.company_name in [“Retool”, “OpenAI”]
not_inValue is not in listExclude titles like “Intern”
(.)Regex/contains matchTitle contains “VP|Director”
geo_distanceWithin radius of locationPeople near San Francisco

Searchable fields

FieldWhat it matchesBest for
basic_profile.namePerson’s full nameFinding a specific person
basic_profile.location.countryCountry nameCountry-level targeting
basic_profile.location.full_locationFull location stringCity or region targeting
experience.employment_details.titleAll titles (current + past)Role-based prospecting
experience.employment_details.current.titleCurrent title onlyCurrent role targeting
experience.employment_details.company_nameAll employers (current + past)Company-based targeting
experience.employment_details.current.company_nameCurrent employer onlyCurrent company targeting
professional_network.location.rawGeographic coordinatesRadius-based search (with geo_distance)

Response fields

Each profile in the response contains these sections:
SectionKey fieldsDescription
basic_profilename, headline, current_title, location, summaryIdentity and location
experienceemployment_details.current, employment_details.pastFull work history
educationschools, all_schools, all_degreesEducation background
skillsprofessional_network_skillsListed skills
contactemails, websitesAvailable contact data
social_handlesprofessional_network_identifier.profile_urlLinkedIn profile URL
professional_networkconnections, profile_picture_permalinkNetwork metadata
metadatalast_scraped_source, updated_atData freshness timestamps

Request parameter reference

ParameterTypeRequiredDefaultDescription
filtersobjectYesFilter condition or condition group. See operators above.
fieldsstring[]NoAllDot-path fields to return (e.g., ["basic_profile.name", "experience.employment_details.current.title"]).
sortsarrayNo[]Sort specifications as an array of { field, order } objects. Use asc or desc for order. Required for stable pagination.
limitintegerNo20Max profiles per page (1–1000).
countintegerNoAlias for limit.
cursorstringNonullPagination cursor from previous response’s next_cursor.
post_processingobjectNoexclude_profiles (URL array) and exclude_names (name array).
previewbooleanNofalseReturn lightweight results (faster, lower cost).
return_querybooleanNofalseDebug flag — include the compiled search query in the response.

Errors

StatusMeaning
400Invalid request — unsupported field, wrong operator, or malformed filters.
401Invalid or missing API key.
403Permission denied or insufficient credits.
500Internal server error. Retry with exponential backoff.

No results

When no people match the filters, the API returns 200 with an empty profiles array:
{
    "profiles": [],
    "next_cursor": null,
    "total_count": 0
}
Action: Broaden filters or check field values with Autocomplete.

API reference summary

DetailValue
EndpointPOST /person/search
AuthBearer token + x-api-version: 2025-11-01
Response{ "profiles": [...], "next_cursor": "...", "total_count": N }
PaginationCursor-based. Pass next_cursor as cursor. Stop when next_cursor is null.
Errors400, 401, 403, 500

What to do next

  • Enrich a profile — once you have a LinkedIn URL from search, use Person Enrich to get the full cached profile.
  • Discover filter values — use Person Autocomplete to find exact indexed values for search filters.
  • See more examples — browse Person Examples for ready-to-copy workflow patterns.
  • Read the quickstart — see Person APIs for a high-level guide to the core person endpoints.
  • Check the API reference — see Search person API reference for the full schema.