---
title: "Search People"
method: POST
path: "/v2/people/search"
tags: ["People"]
---

# Search People

`POST /v2/people/search`

## Request

- Base URL: `https://api.village.ai`
- URL: `https://api.village.ai/v2/people/search`
- Auth: HTTP bearer

Search for people using natural language queries. Pass your search text in the "prompt" field (not "query"). Use this to find professionals matching specific criteria like job titles, companies, industries, or skills. Examples: "engineers at Google", "investors in fintech", "product managers in San Francisco". By default this searches only the caller’s own network; pass scope: "global" to search everyone. Returns matching profiles with relevance scores. Supports cursor-based pagination for large result sets. Expect this to be slow: complex searches usually take 20-60 seconds. Wait for it to finish rather than retrying or assuming it failed.

## Request body

- PeopleSearchRequest: Request body for searching people using natural language and/or structured filters
  - `prompt` string: Natural language search query
  - `filters` object: Structured search filters. Multi-value keys accept an array of values (preferred) or a legacy comma-separated / JSON-array string.
    - `name` string: Person's full name.
    - `linkedinId` union: LinkedIn profile identifier.
      - string
      - string[]
    - `linkedinUrl` union: LinkedIn profile URL.
      - string
      - string[]
    - `locations` string: Structured person locations, as a JSON string: { "locations": [{ "id", "type": "city" | "region" | "country", "name" }], "radius"?: { "value", "unit": "kilometers" } }, 1-60 selections. The ids come from the location picker, so callers without them should use country or city instead.
    - `locationsNot` string: Excludes matches on: Structured person locations, as a JSON string: { "locations": [{ "id", "type": "city" | "region" | "country", "name" }], "radius"?: { "value", "unit": "kilometers" } }, 1-60 selections. The ids come from the location picker, so callers without them should use country or city instead.
    - `timezones` union: Person time zone window, as a JSON object or its JSON string: {"timeZone": "<IANA time zone, e.g. America/New_York>", "withinHours": 0-4} matches people whose city is currently within ± withinHours of that zone's clock (0 = the same UTC offset; daylight saving applies). A list of fixed UTC offsets such as ["UTC-05:00","UTC+02:00"] is also accepted.
      - object
        - `timeZone` string, required
        - `withinHours` integer, required
      - string
      - string[]
    - `timezonesNot` union: Excludes matches on: Person time zone window, as a JSON object or its JSON string: {"timeZone": "<IANA time zone, e.g. America/New_York>", "withinHours": 0-4} matches people whose city is currently within ± withinHours of that zone's clock (0 = the same UTC offset; daylight saving applies). A list of fixed UTC offsets such as ["UTC-05:00","UTC+02:00"] is also accepted.
      - object
        - `timeZone` string, required
        - `withinHours` integer, required
      - string
      - string[]
    - `country` union: Country location.
      - string
      - string[]
    - `countryNot` union: Excludes matches on: Country location.
      - string
      - string[]
    - `city` union: City location.
      - string
      - string[]
    - `cityNot` union: Excludes matches on: City location.
      - string
      - string[]
    - `dropout` true: Confirmed university dropout evidence.
    - `institution` union: School names (exact LinkedIn school name, case-insensitive; short names of the curated schools such as MIT or UPenn also work; look names up with search_institutions) or a school group: Ivy League, Ivy Plus. A group searches every member school and its graduate schools.
      - string
      - string[]
    - `degreeLevel` union: Canonical education degree level. Canonical values: Secondary, Vocational qualification, Short-cycle tertiary, Bachelor's, Postgraduate award, Master's, Graduate Professional, Doctorate.
      - string
      - string[]
    - `educationMajor` union: Canonical education major. Values must be canonical — 220 are allowed, and anything else is rejected.
      - string
      - string[]
    - `educationLinkedinUrl` union: LinkedIn school URL from education history.
      - string
      - string[]
    - `lastJobChangeMonths` integer: Maximum completed months since the latest qualifying job change.
    - `yearsOfExperienceMin` integer: Minimum total years of professional experience.
    - `yearsOfExperienceMax` integer: Maximum total years of professional experience.
    - `averageTenureMonthsMin` integer: Minimum average tenure per valid recorded role in months.
    - `averageTenureMonthsMax` integer: Maximum average tenure per valid recorded role in months.
    - `roleDurationMonthsMin` integer: Minimum current recorded role duration in months.
    - `roleDurationMonthsMax` integer: Maximum current recorded role duration in months.
    - `pastRoleDurationMonthsMin` integer: Minimum past recorded role duration in months.
    - `pastRoleDurationMonthsMax` integer: Maximum past recorded role duration in months.
    - `currentRoleTenureMonthsMin` integer: Minimum standardized tenure in the current role in completed months.
    - `currentRoleTenureMonthsMax` integer: Maximum standardized tenure in the current role in completed months.
    - `position` union: Current job title(s).
      - string
      - string[]
    - `pastPosition` union: Previous job title(s) — held before, not currently.
      - string
      - string[]
    - `seniority` union: Current standardized seniority level(s) (canonical taxonomy labels). Canonical values: Owner, Founder, C-suite, Partner, VP, Head, Director, Manager, Senior, Entry, Intern.
      - string
      - string[]
    - `seniorityNot` union: Excludes matches on: Current standardized seniority level(s) (canonical taxonomy labels). Canonical values: Owner, Founder, C-suite, Partner, VP, Head, Director, Manager, Senior, Entry, Intern.
      - string
      - string[]
    - `pastSeniority` union: Previous standardized seniority level(s) (canonical taxonomy labels) — held before, not currently. Canonical values: Owner, Founder, C-suite, Partner, VP, Head, Director, Manager, Senior, Entry, Intern.
      - string
      - string[]
    - `pastSeniorityNot` union: Excludes matches on: Previous standardized seniority level(s) (canonical taxonomy labels) — held before, not currently. Canonical values: Owner, Founder, C-suite, Partner, VP, Head, Director, Manager, Senior, Entry, Intern.
      - string
      - string[]
    - `department` union: Current standardized department(s) (canonical taxonomy labels). Canonical values: C-Suite, Engineering & Technical, Design, Education, Finance, Human Resources, Information Technology, Legal, Marketing, Medical & Health, Operations, Sales, Consulting.
      - string
      - string[]
    - `departmentNot` union: Excludes matches on: Current standardized department(s) (canonical taxonomy labels). Canonical values: C-Suite, Engineering & Technical, Design, Education, Finance, Human Resources, Information Technology, Legal, Marketing, Medical & Health, Operations, Sales, Consulting.
      - string
      - string[]
    - `pastDepartment` union: Previous standardized department(s) (canonical taxonomy labels) — held before, not currently. Canonical values: C-Suite, Engineering & Technical, Design, Education, Finance, Human Resources, Information Technology, Legal, Marketing, Medical & Health, Operations, Sales, Consulting.
      - string
      - string[]
    - `pastDepartmentNot` union: Excludes matches on: Previous standardized department(s) (canonical taxonomy labels) — held before, not currently. Canonical values: C-Suite, Engineering & Technical, Design, Education, Finance, Human Resources, Information Technology, Legal, Marketing, Medical & Health, Operations, Sales, Consulting.
      - string
      - string[]
    - `function` union: Current standardized job function(s) (canonical taxonomy labels). Values must be canonical — 219 are allowed, and anything else is rejected.
      - string
      - string[]
    - `functionNot` union: Excludes matches on: Current standardized job function(s) (canonical taxonomy labels). Values must be canonical — 219 are allowed, and anything else is rejected.
      - string
      - string[]
    - `pastFunction` union: Previous standardized job function(s) (canonical taxonomy labels) — held before, not currently. Values must be canonical — 219 are allowed, and anything else is rejected.
      - string
      - string[]
    - `pastFunctionNot` union: Excludes matches on: Previous standardized job function(s) (canonical taxonomy labels) — held before, not currently. Values must be canonical — 219 are allowed, and anything else is rejected.
      - string
      - string[]
    - `roleGroups` union: Alternative current roles the flat seniority / department / function keys cannot express: an array of 1-6 groups, each { "seniority"?: string[], "department"?: string[], "function"?: string[] } using the canonical labels of those keys. Groups are OR-ed, the axes inside a group must hold on the same current role, and the key ANDs with every other filter. The JSON string of the array is accepted too. An unknown label is rejected with the accepted vocabulary.
      - string
      - object[]
        - `seniority` string[]
        - `department` string[]
        - `function` string[]
    - `company` union: Current company name(s).
      - string
      - string[]
    - `companyNot` union: Excludes matches on: Current company name(s).
      - string
      - string[]
    - `pastCompany` union: Previous company name(s) — held before, not currently.
      - string
      - string[]
    - `pastCompanyNot` union: Excludes matches on: Previous company name(s) — held before, not currently.
      - string
      - string[]
    - `everCompany` union: Current or previous company name(s) (any point in their career).
      - string
      - string[]
    - `everCompanyNot` union: Excludes matches on: Current or previous company name(s) (any point in their career).
      - string
      - string[]
    - `recentCompany` union: Current company name(s), or previous company name(s) left within the last 2 years.
      - string
      - string[]
    - `recentCompanyNot` union: Excludes matches on: Current company name(s), or previous company name(s) left within the last 2 years.
      - string
      - string[]
    - `companySize` string: Current company employee count.
    - `companySizeNot` string: Excludes matches on: Current company employee count.
    - `pastCompanySize` string: Previous company employee count — held before, not currently.
    - `pastCompanySizeNot` string: Excludes matches on: Previous company employee count — held before, not currently.
    - `companyDomain` string: Current company website domain.
    - `pastCompanyDomain` string: Previous company website domain — held before, not currently.
    - `everCompanyDomain` string: Current or previous company website domain (any point in their career).
    - `recentCompanyDomain` string: Current company website domain, or previous company website domain left within the last 2 years.
    - `companyLinkedinUrl` union: Current company LinkedIn URL or identifier.
      - string
      - string[]
    - `pastCompanyLinkedinUrl` union: Previous company LinkedIn URL or identifier — held before, not currently.
      - string
      - string[]
    - `everCompanyLinkedinUrl` union: Current or previous company LinkedIn URL or identifier (any point in their career).
      - string
      - string[]
    - `recentCompanyLinkedinUrl` union: Current company LinkedIn URL or identifier, or previous company LinkedIn URL or identifier left within the last 2 years.
      - string
      - string[]
    - `companyIndustry` union: Current company industry (canonical LinkedIn industries). Values must be canonical — 487 are allowed, and anything else is rejected.
      - string
      - string[]
    - `companyIndustryNot` union: Excludes matches on: Current company industry (canonical LinkedIn industries). Values must be canonical — 487 are allowed, and anything else is rejected.
      - string
      - string[]
    - `pastCompanyIndustry` union: Previous company industry (canonical LinkedIn industries) — held before, not currently. Values must be canonical — 487 are allowed, and anything else is rejected.
      - string
      - string[]
    - `pastCompanyIndustryNot` union: Excludes matches on: Previous company industry (canonical LinkedIn industries) — held before, not currently. Values must be canonical — 487 are allowed, and anything else is rejected.
      - string
      - string[]
    - `companyKeywords` union: Company profile keywords (full-text over name, about, specialties, categories, slogan).
      - string
      - string[]
    - `companyFundingStage` union: Current company most-recent funding round stage (e.g., "Series B"). Matches the latest round only. Canonical values: Seed, Pre seed, Angel, Series A, Series B, Series C, Series D, Series E, Series F, Series G, Series H, Series I, Series J, Series unknown, Private equity, Post IPO equity, Post IPO debt, Post IPO secondary, Debt financing, Convertible note, Corporate round, Grant, Non equity assistance, Equity crowdfunding, Product crowdfunding, Initial coin offering, Secondary market, Undisclosed.
      - string
      - string[]
    - `companyFundingStageNot` union: Excludes matches on: Current company most-recent funding round stage (e.g., "Series B"). Matches the latest round only. Canonical values: Seed, Pre seed, Angel, Series A, Series B, Series C, Series D, Series E, Series F, Series G, Series H, Series I, Series J, Series unknown, Private equity, Post IPO equity, Post IPO debt, Post IPO secondary, Debt financing, Convertible note, Corporate round, Grant, Non equity assistance, Equity crowdfunding, Product crowdfunding, Initial coin offering, Secondary market, Undisclosed.
      - string
      - string[]
    - `hiring` union: Open job title(s) the current employer is hiring for.
      - string
      - string[]
    - `hiringMinOpenings` integer: Minimum number of qualifying open jobs at the current employer (with hiring: openings matching those titles).
    - `pastCompanyKeywords` union: Previous company keywords.
      - string
      - string[]
  - `limit` integer: Maximum number of results per page
  - `mode` 'auto' | 'lookup' | 'simple' | 'complex': Search execution mode. "auto" classifies the query into lookup/simple/complex. Use "lookup" for direct matches, "simple" for firmographic queries, and "complex" for multi-step or subjective queries.
  - `stream` boolean: Enable Server-Sent Events (SSE) streaming for real-time results
  - `scope` 'network' | 'global' | 'specific_list': Override default scope. Defaults: lookup=global, simple=network, complex=network. "network" searches your connections first, "global" searches everyone.
  - `cursor` union: Pagination cursor (encoded string or cursor object)
    - string
    - SearchCursor: Cursor for paginated search results
      - `source` 'network' | 'global'
      - `chunk_skip` integer
      - `results_skip` integer
      - `cumulative_results` integer
    - object
      - `source` 'network' | 'network_pool' | 'global', required
      - `chunkSkip` integer, required
      - `resultsSkip` integer, required
      - `networkAfter` object, nullable
        - `score` number, required
        - `docId` string, required
      - `searchType` 'people', required
      - `filtersHash` string, required
      - `resolvedMode` 'simple' | 'complex'
      - `networkQuery` string
      - `globalQuery` string
      - `sqlSignature` string
      - `poolToken` string
      - `poolPauses` integer
  - `network_filters` NetworkFilters: Network filtering options for people search
    - `connection_degrees` integer[]
    - `introducer_linkedin_ids` string[]
    - `user_to_introducer_types` string[]
    - `user_to_introducer_min_score` 'excellent' | 'very_good' | 'good' | 'okay' | 'maybe' | 'no_path'
    - `introducer_to_target_types` string[]
    - `introducer_to_target_min_score` 'excellent' | 'very_good' | 'good' | 'okay' | 'maybe' | 'no_path'
    - `exclude_teams` boolean
    - `exclude_community` boolean
  - `include_counts` 'global' | 'network' | 'all': Inline count scopes to compute on the first page only. Use "global", "network", or "all". Ignored when cursor is provided and adds latency.
  - `specific_list_data` object: Required when scope="specific_list". Provides the caller-supplied candidate set (1..50,000 entries). Each entry is either a bare LinkedIn identifier or { id, score? }. Results are restricted to people matching identifiers in this list; the request limit is ignored and all matches are returned in a single response.
    - `people_linkedin_identifiers` union[], required
      - union
        - string
        - object
          - `id` string, required
          - `score` number, nullable
  - `list_filter` object: Search within your saved lists. people_list_id restricts results to the members of that people list; company_list_id restricts results to people whose current employer is in that company list. Both may be combined (AND) and with any prompt or filter. A list alone is a valid search. Lists must belong to your active workspace.
    - `people_list_id` integer
    - `company_list_id` integer
  - `screening_handoff` boolean: Complex searches keep only objective constraints in SQL and return the subjective ones as metadata.screening_criteria for a downstream screening step.

## Response `200`

Search completed successfully

- object
  - `data` SearchPerson[], required
    - `id` integer, required: Postgres ID
    - `first_name` string, required: First name
    - `last_name` string, required: Last name
    - `full_name` string, nullable: Full name (computed)
    - `linkedin_url` string, uri, nullable: LinkedIn profile URL
    - `headline` string, nullable: Professional headline
    - `about_me` string, nullable: LinkedIn bio/summary
    - `location` Location, nullable: Geographic location
      - `city` string, nullable
      - `state` string, nullable
      - `country` string, nullable
    - `work_relevant` Work, nullable: Relevant job position based on the search
      - `title` string, nullable: Job title
      - `company` WorkCompany, nullable: Company object
        - `id` integer, nullable, required: Postgres company ID, or null when the employer has not been resolved
        - `name` string, required: Company name
        - `linkedin_url` string, uri, nullable: LinkedIn company page URL
        - `domain` string, nullable: Company website domain
        - `website` string, nullable: Company website stored in Postgres
        - `industry` string, nullable: Primary industry
        - `employee_count` integer, nullable: Number of employees
        - `image_url` string, uri, nullable: Company logo URL
        - `location` object, nullable: Company HQ location
          - `city` string, nullable
          - `state` string, nullable
          - `country` string, nullable
        - `headquarters` string, nullable: Raw headquarters string
        - `type` string, nullable: Company type (e.g. Public, Private)
        - `founded_year` integer, nullable: Year the company was founded
        - `funding` union: Funding data, passed through from storage as-is. Two shapes are possible and callers must handle both: an OBJECT summarising the most-recent round (keys `last_round_stage`, `price`, `investors`, `last_round_date`, `number_of_rounds`), or an ARRAY of per-round objects (keys `date`, `type`, `amount`, `currency`, `investors`) written by the refresh pipeline. An empty array means no funding data, which is the large majority of companies. All money, date and count fields are display strings, not numbers or ISO dates — don't parse or range-filter them.
          - object
            - `price` string, nullable
            - `investors` object[], nullable
              - …
            - `last_round_date` string, nullable
            - `last_round_stage` string, nullable
            - `number_of_rounds` union
              - …
          - object[]
            - `date` string, nullable
            - `type` string, nullable
            - `amount` union
              - …
            - `currency` string, nullable
            - `investors` string, nullable
          - unknown
      - `start_date` string, nullable: Start date (YYYY-MM-DD)
      - `end_date` string, nullable: End date (YYYY-MM-DD), null if current
    - `image_url` string, uri, nullable: Profile image URL
    - `last_enrichment_at` string, nullable: ISO 8601 timestamp of the last refresh from the data provider. Null when the profile has never been refreshed.
  - `metadata` object, required
    - `request_id` string, required
    - `mode` 'lookup' | 'simple' | 'complex'
    - `source` 'network' | 'global'
    - `network_stage_complete` boolean
    - `generated_sql` string
    - `search_engine` string
    - `counts_token` string
    - `search_execution_token` string
    - `counts` object
      - `global` object
        - `value` number, nullable, required
        - `is_capped` boolean, required
        - `cap` number, required
      - `network` object
        - `value` number, nullable, required
        - `is_estimated` boolean, required
    - `cache_hit` boolean
    - `plan_disclosure` object: Present only when the prompt-to-filters engine served the search: the filters it ran on, in words, and every approximation it made.
      - `sentence` string, required
      - `approximations` string[], required
  - `pagination` PaginationInfo, required: Cursor-based pagination metadata
    - `cursor` string, nullable, required: Opaque cursor for fetching the next page (null if no more results)
    - `has_next_page` boolean, required: Whether more results are available
    - `count` integer, required: Total number of results or count of items in current page

## Other responses

- `400`: Bad request - invalid parameters
- `401`: Unauthorized - missing or invalid authentication
- `422`: Validation error - invalid request format

---

[API](https://skmtc.dev/village/apis/village-v2-api.md) - [All operations](https://skmtc.dev/village/apis/village-v2-api/llms.txt) - [OpenAPI document](https://skmtc.dev/village/apis/village-v2-api/revisions/aebe21a1a544?raw)
