---
title: "Enrich Person"
method: POST
path: "/v2/people/enrich"
tags: ["People"]
---

# Enrich Person

`POST /v2/people/enrich`

## Request

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

Get detailed profile information for a person. Use this to look up professional details when you have a LinkedIn URL. Returns: full name, headline, current title and company, location, profile photo URL, and LinkedIn URL. On a cache miss the profile is fetched live from HarvestAPI (public LinkedIn data) and saved to Village. Useful for enriching CRM records or preparing for outreach. People can have their data removed by emailing privacy@village.ai or support@village.ai.

## Request body

- union: Request for basic person enrichment
  - object: Person by LinkedIn URL
    - `linkedin_url` string, required: LinkedIn person profile URL
    - `mode` 'cached_first' | 'cached_only' | 'realtime_only': How to source the data. `cached_first` (default): return Village's cached profile if it is recent, otherwise fetch live — credited only when it fetches. `cached_only`: never fetch live, and report a miss when the profile is not already cached (404 on the single endpoints, a per-item not-found on the bulk ones) — never credited. `realtime_only`: always fetch live, and credited whenever that fetch returns data; a fetch that finds nothing is still free.
  - object: Person by generic URL (auto-detected)
    - `url` string, required: Generic URL (auto-detected)
    - `mode` 'cached_first' | 'cached_only' | 'realtime_only': How to source the data. `cached_first` (default): return Village's cached profile if it is recent, otherwise fetch live — credited only when it fetches. `cached_only`: never fetch live, and report a miss when the profile is not already cached (404 on the single endpoints, a per-item not-found on the bulk ones) — never credited. `realtime_only`: always fetch live, and credited whenever that fetch returns data; a fetch that finds nothing is still free.

## Response `200`

Person enriched successfully

- object
  - `data` EnrichBasicResponse, required: Response for basic person enrichment
    - `full_name` string, required
    - `linkedin_url` string, required
    - `avatar` string
    - `headline` string, nullable, required: LinkedIn headline
    - `location` Location, nullable, required: Geographic location
      - `city` string, nullable
      - `state` string, nullable
      - `country` string, nullable
    - `work_relevant` WorkRelevant, nullable, required: Current or most relevant work position and company
      - `title` string, required
      - `start_date` string, nullable, required
      - `end_date` string, nullable, required
      - `company` object, nullable, required: Employer information, including employers not yet resolved to Postgres
        - `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
    - `work_history` WorkExperience[], required
      - `title` string, required
      - `start_date` string, nullable, required
      - `end_date` string, nullable, required
      - `company` object, nullable, required: Employer information, including employers not yet resolved to Postgres
        - `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
    - `last_enrichment_at` string, nullable, required: ISO 8601 timestamp of the last refresh from a third-party data provider. Null when the profile has never been provider-enriched (network-synced data only). Use it to judge staleness before paying for a realtime_only re-enrich.
  - `metadata` object, required
    - `request_id` string, required

## Other responses

- `400`: Bad request - invalid parameters
- `401`: Unauthorized - missing or invalid authentication
- `404`: Person not found
- `503`: Enrichment temporarily unavailable - retry
- `504`: Enrichment timed out - retry

---

[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)
