> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enricho.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Search people

> Free person previews or full records at one credit per returned person.

All filters are optional; `{}` is an unfiltered paid full search. Different fields combine with AND; list values combine with OR. `person_id` and `linkedin_url` resolve into one set of alternative person IDs. List filters accept one string or at most 100 strings. Each value and `query` is limited to 200 UTF-8 bytes before normalization.

## Preview

```bash theme={null}
curl -X POST 'https://mcp.enricho.co/api/directory/people/search' \
  -H 'Authorization: Bearer enr_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"country_code":"GB","job_title":["engineer","developer"],"preview":true}'
```

A preview returns at most 10 people for 0 credits. `limit` and `cursor` are ignored. `has_more` indicates additional matches, but `next_cursor` is empty and no count is exposed. Nonempty `exclude_person_ids` is rejected; `exclude_company_domains` allows at most 10 values. [Daily preview caps](https://docs.enricho.co/api-reference/overview.md) apply.

Preview fields: `person_id`, `full_name`, `job_title`, `seniority`, `company_name`, `company_domain`, `industry`, `employee_size_band`, `city`, `country`, `country_code`, `has_email`, `has_phone`, `has_linkedin`. Contact values and profile URLs are not returned. Flags describe cleaned contact presence, not verification or deliverability.

## Full retrieval

Replace the ID with one from your own preview, or repeat its filters with `preview: false`:

```bash theme={null}
curl -X POST 'https://mcp.enricho.co/api/directory/people/search' \
  -H 'Authorization: Bearer enr_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"person_id":["PERSON_ID_FROM_PREVIEW"],"preview":false,"limit":1}'
```

Continuation example (only use a cursor from a full search with the same filters):

```bash theme={null}
curl -X POST 'https://mcp.enricho.co/api/directory/people/search' \
  -H 'Authorization: Bearer enr_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"company_domain":"example.com","limit":5,"cursor":"NEXT_CURSOR_FROM_PREVIOUS_RESPONSE"}'
```

Full pages cost 1 credit per returned person, including repeats; empty pages cost 0. Default page size is 20, maximum 100. Insufficient balance for the whole page returns 402 without records or a debit. [Pagination and retry precautions](https://docs.enricho.co/api-reference/overview.md) apply.

## Matching

* `email`: exact primary or alternate email, lowercased.
* `full_name`, `company_name`, `job_title`, `role`: case-insensitive substrings; role underscores normalize to spaces.
* `industry`: substring in either person or employer industry.
* `city`, `country_code`, `company_id`, `company_domain`: exact after normalization. Country codes are uppercased; domains lowercased without schemes, paths or leading `www.`. IDs remain case-sensitive.
* `linkedin_url`: a LinkedIn profile `/in/<slug>` URL, converted to an ID; company URLs are invalid.
* `seniority`: stored level or title-derived matches, including `c_suite`, `vp`, `director`, `head`, `manager`, `founder`, `owner`, `partner`, `senior`, `entry`. Aliases include executive, vice president and junior. Unknown values can match their own title words; this is not a strict enum.
* `employee_size_band`: stored employer-size label, not a numeric range. `skill`: any matching stored skill, lowercased.
* `has_email`, `has_phone`, `has_linkedin`: true restricts stored contact presence; false does not mean missing. Read-time cleaning can remove an invalid stored phone even if the presence filter matched.
* `exclude_person_ids`, `exclude_company_domains`: exclusion lists; full searches accept up to 100 each.
* `query`: every retained term must match searchable name, email, title, role, seniority, employer, industry or location text. Terms are lowercased, common stop words removed, and at most 10 distinct terms retained. This is not Boolean query syntax.

## Full record fields

Expand the response schema for every exact field and nested employer shape. Full records include names; primary/alternate email and phone; email type; available demographic and income fields; role, seniority, skills, interests and experience; address/location; social URLs; `company`; `extras`; and `updated_at`.

Unavailable strings are `""`, nullable numbers are `null`, arrays may be `[]`, and `extras` is `{}` when absent. `company` is null if no company ID is associated. Extra keys vary by record. Do not assume unavailable fields are omitted or that contacts are verified; `updated_at` is an update timestamp, not a verification timestamp.


## OpenAPI

````yaml api-reference/openapi.json POST /api/directory/people/search
openapi: 3.1.0
info:
  title: Enricho Public REST API
  version: 1.0.0
  description: >-
    Public directory search and billing APIs. Full search costs 1 credit per
    returned record; previews and usage calls use no credits. Request and
    response contracts reflect the current public gateway and service handlers.
servers:
  - url: https://mcp.enricho.co
security:
  - apiKey: []
  - headerKey: []
tags:
  - name: Directory
  - name: Billing
paths:
  /api/directory/people/search:
    post:
      tags:
        - Directory
      summary: Search people
      description: >-
        All filters are optional. Full searches cost 1 credit per returned
        record, not per page; no matches use 0 credits. Each retrieval,
        including repeats and continuation pages, is charged again. A page is
        released only after an atomic full-page debit is confirmed. On an
        unconfirmed charge (503), no records are returned; check GET
        /api/billing/usage before retrying. Preview returns at most 10 records
        for free, ignores limit/cursor and is capped per user per UTC day.
        Public searches do not return total counts.
      operationId: searchPeople
      requestBody:
        required: false
        description: 'Send JSON with Content-Type: application/json.'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchPeopleRequest'
            examples:
              preview:
                summary: Free preview
                value:
                  country_code: GB
                  job_title:
                    - engineer
                    - developer
                  preview: true
              full:
                summary: Full paid page
                value:
                  company_domain: example.com
                  limit: 5
      responses:
        '200':
          description: Success envelope.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    const: true
                  result:
                    anyOf:
                      - $ref: '#/components/schemas/PeoplePage'
                      - $ref: '#/components/schemas/PeoplePreviewPage'
                  message:
                    type: string
                required:
                  - success
                  - result
                  - message
        '400':
          description: >-
            bad_request: malformed JSON, invalid full-search limit, or cursor
            invalid / from different filters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 'unauthorized: missing, invalid or revoked API key.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: >-
            insufficient_credits: insufficient balance for the entire page. No
            records returned and no credits deducted; reduce limit or buy
            credits.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            validation_failed: unknown field, wrong type, excessive list/value
            length, invalid LinkedIn profile URL or disallowed preview
            exclusions. query_too_broad: narrow the search and retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: >-
            rate_limited: key, account or IP request limit exceeded; wait a
            minute before retrying. Preview daily caps also return this status;
            wait until midnight UTC or use a paid full search.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: 'internal: unexpected server failure.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: 'upstream_unavailable: gateway could not reach the service.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            upstream_unavailable: authentication, directory, preview counter or
            billing dependency unavailable. An unconfirmed full-search charge
            returns no records but may already have debited credits; inspect
            usage before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    SearchPeopleRequest:
      type: object
      additionalProperties: false
      properties:
        person_id:
          description: >-
            Exact person IDs from search results. Values are case-sensitive.
            Combined with linkedin_url as alternative person IDs. Accepts a
            single string or up to 100 strings; each value is limited to 200
            UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        linkedin_url:
          description: >-
            LinkedIn profile URLs with /in/<slug>. Converted to person IDs and
            combined with person_id as alternatives. Company URLs are invalid.
            Accepts a single string or up to 100 strings; each value is limited
            to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        email:
          description: >-
            Exact primary or alternate email matches, normalized to lowercase.
            Accepts a single string or up to 100 strings; each value is limited
            to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        full_name:
          description: >-
            Case-insensitive full-name substring matches. Accepts a single
            string or up to 100 strings; each value is limited to 200 UTF-8
            bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        company_name:
          description: >-
            Case-insensitive employer-name substring matches. Accepts a single
            string or up to 100 strings; each value is limited to 200 UTF-8
            bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        job_title:
          description: >-
            Case-insensitive job-title substring matches. Accepts a single
            string or up to 100 strings; each value is limited to 200 UTF-8
            bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        seniority:
          description: >-
            Stored seniority or inferred title-level matches. Common levels:
            c_suite, vp, director, head, manager, founder, owner, partner,
            senior, entry. Aliases include c-level, executive, vice president,
            co-founder, junior and intern. Unknown values match their own title
            words. Accepts a single string or up to 100 strings; each value is
            limited to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        role:
          description: >-
            Case-insensitive role substring matches; underscores normalize to
            spaces. Accepts a single string or up to 100 strings; each value is
            limited to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        country_code:
          description: >-
            Country codes, uppercased (for example GB or US). Accepts a single
            string or up to 100 strings; each value is limited to 200 UTF-8
            bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        city:
          description: >-
            Case-insensitive exact city matches. Accepts a single string or up
            to 100 strings; each value is limited to 200 UTF-8 bytes before
            normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        company_id:
          description: >-
            Exact employer company IDs, case-sensitive. Accepts a single string
            or up to 100 strings; each value is limited to 200 UTF-8 bytes
            before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        company_domain:
          description: >-
            Exact employer domains, lowercased; URL schemes, paths and leading
            www. are removed. Accepts a single string or up to 100 strings; each
            value is limited to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        industry:
          description: >-
            Case-insensitive substring matches in the person industry or
            employer industry. Accepts a single string or up to 100 strings;
            each value is limited to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        employee_size_band:
          description: >-
            Stored employer employee-size band (for example 1-10 or 51-200), not
            a numeric range comparison. Accepts a single string or up to 100
            strings; each value is limited to 200 UTF-8 bytes before
            normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        skill:
          description: >-
            Any matching skill in the comma-separated skill list, normalized to
            lowercase. Accepts a single string or up to 100 strings; each value
            is limited to 200 UTF-8 bytes before normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        exclude_company_domains:
          description: >-
            Exclude these normalized employer domains. Full search: up to 100
            values; preview: up to 10. Accepts a single string or up to 100
            strings; each value is limited to 200 UTF-8 bytes before
            normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        exclude_person_ids:
          description: >-
            Exclude exact person IDs. Only available in full searches; any
            nonempty list is rejected in preview. Accepts a single string or up
            to 100 strings; each value is limited to 200 UTF-8 bytes before
            normalization.
          oneOf:
            - type: string
              maxLength: 200
            - type: array
              maxItems: 100
              items:
                type: string
                maxLength: 200
        query:
          type: string
          maxLength: 200
          description: >-
            Free text, limited to 200 UTF-8 bytes. Up to 10 distinct lowercased
            terms after splitting on whitespace, commas and semicolons and
            removing common stop words. Every retained term must match a
            searchable text field; this is not a Boolean query language.
        has_email:
          type: boolean
          default: false
          description: >-
            Require a stored primary email. false or omission adds no
            restriction; it does not search for missing data. Stored presence
            does not guarantee a valid cleaned value.
        has_phone:
          type: boolean
          default: false
          description: >-
            Require a stored primary or alternate phone. false or omission adds
            no restriction; it does not search for missing data. Stored presence
            does not guarantee a valid cleaned value.
        has_linkedin:
          type: boolean
          default: false
          description: >-
            Require a stored LinkedIn profile URL. false or omission adds no
            restriction; it does not search for missing data. Stored presence
            does not guarantee a valid cleaned value.
        preview:
          type: boolean
          default: false
          description: >-
            true returns a free first-page preview of up to 10 records. limit
            and cursor are ignored; previews cannot be paginated. false returns
            full records at 1 credit each.
        limit:
          type: integer
          minimum: 0
          maximum: 100
          default: 20
          description: >-
            Full search page size, 1–100. Omitted or 0 uses 20. Negative values
            or values above 100 return 400. Ignored in preview.
        cursor:
          type: string
          default: ''
          description: >-
            Opaque next_cursor from a previous full search with the same
            filters. Omit or use an empty string for the first page. Ignored in
            preview.
      description: >-
        All fields are optional; {} searches without filters. Different filter
        fields combine with AND; multiple values in a filter combine with OR.
        Record-ID exclusions are full-search only.
    PeoplePage:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/Person'
          maxItems: 100
        next_cursor:
          type: string
          description: Opaque continuation token; empty when no next page is available.
        has_more:
          type: boolean
          description: Whether a continuation page is available.
        credits_used:
          type: integer
          minimum: 0
          maximum: 100
          description: 1 per returned record; 0 for an empty page.
      required:
        - results
        - next_cursor
        - has_more
        - credits_used
      description: No total_estimate or total_capped fields are returned by public search.
    PeoplePreviewPage:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/PersonPreview'
          maxItems: 10
        next_cursor:
          type: string
          description: Always empty; previews cannot be paginated.
        has_more:
          type: boolean
          description: More matches exist beyond the preview; not a total count.
        credits_used:
          type: integer
          minimum: 0
          const: 0
          description: Always 0.
      required:
        - results
        - next_cursor
        - has_more
        - credits_used
      description: No total_estimate or total_capped fields are returned by public search.
    Error:
      type: object
      properties:
        success:
          type: boolean
          const: false
        result:
          type: object
          properties:
            code:
              type: string
              description: Machine-readable error code.
          required:
            - code
        message:
          type: string
          description: Human-readable error; do not parse this as a stable identifier.
      required:
        - success
        - result
        - message
    Person:
      type: object
      properties:
        person_id:
          type: string
        first_name:
          type: string
        middle_name:
          type: string
        last_name:
          type: string
        full_name:
          type: string
        email:
          type: string
        alternate_email:
          type: string
        email_type:
          type: string
        phone:
          type: string
        alternate_phone:
          type: string
        gender:
          type: string
        age:
          type:
            - integer
            - 'null'
          format: int32
        birth_year:
          type:
            - integer
            - 'null'
          format: int32
        birth_month:
          type:
            - integer
            - 'null'
          format: int32
        birth_date:
          type:
            - integer
            - 'null'
          format: int32
        estimated_income:
          type: string
        income_min:
          type:
            - integer
            - 'null'
          format: int32
        income_max:
          type:
            - integer
            - 'null'
          format: int32
        job_title:
          type: string
        seniority:
          type: string
        role:
          type: string
        industry:
          type: string
        skills:
          type: array
          items:
            type: string
        interests:
          type: array
          items:
            type: string
        years_experience:
          type:
            - integer
            - 'null'
          format: int32
        address:
          type: string
        city:
          type: string
        region:
          type: string
        zip_code:
          type: string
        country:
          type: string
        country_code:
          type: string
        continent:
          type: string
        countries:
          type: array
          items:
            type: string
        linkedin_url:
          type: string
        linkedin_connections:
          type:
            - integer
            - 'null'
          format: int32
        x_url:
          type: string
        instagram_url:
          type: string
        tiktok_url:
          type: string
        facebook_url:
          type: string
        github_url:
          type: string
        company:
          anyOf:
            - $ref: '#/components/schemas/PersonCompany'
            - type: 'null'
          description: >-
            Current employer and available company details; null if no company
            ID is associated with the person.
        extras:
          type: object
          additionalProperties:
            type: string
          description: >-
            Additional record attributes as string key/value pairs. Keys vary by
            record; do not rely on a fixed set.
        updated_at:
          type: string
          format: date-time
      required:
        - person_id
        - first_name
        - middle_name
        - last_name
        - full_name
        - email
        - alternate_email
        - email_type
        - phone
        - alternate_phone
        - gender
        - age
        - birth_year
        - birth_month
        - birth_date
        - estimated_income
        - income_min
        - income_max
        - job_title
        - seniority
        - role
        - industry
        - skills
        - interests
        - years_experience
        - address
        - city
        - region
        - zip_code
        - country
        - country_code
        - continent
        - countries
        - linkedin_url
        - linkedin_connections
        - x_url
        - instagram_url
        - tiktok_url
        - facebook_url
        - github_url
        - company
        - extras
        - updated_at
      description: >-
        Full record. Field availability varies: absent text is an empty string,
        nullable numbers are null, arrays may be empty, and extras is {} when
        unavailable. updated_at is the record update timestamp, not a
        verification guarantee.
    PersonPreview:
      type: object
      properties:
        person_id:
          type: string
        full_name:
          type: string
        job_title:
          type: string
        seniority:
          type: string
        company_name:
          type: string
        company_domain:
          type: string
        industry:
          type: string
        employee_size_band:
          type: string
        city:
          type: string
        country:
          type: string
        country_code:
          type: string
        has_email:
          type: boolean
        has_phone:
          type: boolean
        has_linkedin:
          type: boolean
      required:
        - person_id
        - full_name
        - job_title
        - seniority
        - company_name
        - company_domain
        - industry
        - employee_size_band
        - city
        - country
        - country_code
        - has_email
        - has_phone
        - has_linkedin
      description: >-
        Identity, professional and location fields only. Flags describe whether
        cleaned contact values exist; contact values and profile URLs are not
        returned.
    PersonCompany:
      type: object
      properties:
        company_id:
          type: string
        name:
          type: string
        domain:
          type: string
        industry:
          type: string
        employee_size_band:
          type: string
        size_min:
          type:
            - integer
            - 'null'
          format: int32
        size_max:
          type:
            - integer
            - 'null'
          format: int32
        website:
          type: string
        phone:
          type: string
        address:
          type: string
        country:
          type: string
        country_code:
          type: string
        linkedin_url:
          type: string
        x_url:
          type: string
        facebook_url:
          type: string
      required:
        - company_id
        - name
        - domain
        - industry
        - employee_size_band
        - size_min
        - size_max
        - website
        - phone
        - address
        - country
        - country_code
        - linkedin_url
        - x_url
        - facebook_url
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: Enricho API key (enr_...)
    headerKey:
      type: apiKey
      in: header
      name: X-Api-Key
      description: >-
        An Enricho API key (enr_...). Use this or Authorization: Bearer, not
        both.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.