---
title: "Search for people"
method: POST
path: "/api/v1/enrichment/people-search"
tags: ["Enrichment"]
---

# Search for people

`POST /api/v1/enrichment/people-search`

## Request

- Base URL: `https://api.rodz.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.rodz.io/api/v1/enrichment/people-search`
- Auth: HTTP bearer

Find LinkedIn profiles at target companies with specific job titles or seniority levels—each result includes an AI-verified qualification verdict showing whether the profile actually matches your criteria.

**Input:** filter criteria—`companies` (names, LinkedIn URLs, or IDs), `jobTitles`, `excludeJobTitles`, `locations`, `geoIds`, `seniorityLevels`, `companySize`, `industryId` (LinkedIn industry IDs, resolve via `/enrichment/linkedin-industries`), `companyHeadquarterLocations` (where the company is headquartered, as opposed to `locations` which is where the person is), plus `excludeIndustryId` and `excludeCompanyHeadquarterLocations`; `page` for pagination (1-100, up to 25 results per page). Optional: `webhookUrl` and `deliveryMode` for async delivery, `qualifiedOnly` to exclude disqualified matches, `metadata` to correlate responses.

**Output:** (sync: 200 OK, or async: 202 Accepted → webhook POST) Array of up to 25 LinkedIn profiles per page with `linkedinUrl`, `firstName`, `lastName`, `location`, `openProfile`, `premium`, and `currentPositions` (company name, title, LinkedIn URL, start date). Each profile includes `qualificationStatus` (QUALIFIED or DISQUALIFIED) and `qualificationReason` explaining the verdict. Response includes pagination metadata (`count`, `page`, `totalPages`, `total`, `hasMore`) and `aiValidationStatus` (ok or unavailable—if unavailable, all results default to QUALIFIED so the response stays usable).

## Request body

- object: JSON body for POST /api/v1/enrichment/people-search.
  - `companies` string[], nullable: Company names, LinkedIn company URLs, or numeric LinkedIn company IDs. Mix freely in the same array. Max 50.
  - `jobTitles` string[], nullable: Current job titles to include. Max 70.
  - `excludeJobTitles` string[], nullable: Job titles to exclude. Max 70.
  - `locations` string[], nullable: Location names (e.g. France, San Francisco). Each entry is one place: a qualified name such as "Lyon, France" is resolved as a whole, and a name that cannot be resolved returns 422 UNRESOLVED_LOCATION. For precise filtering, use geoIds instead.
  - `geoIds` string[], nullable: LinkedIn geo IDs for precise location filtering. Use /enrichment/linkedin-geo-id to resolve.
  - `seniorityLevels` string[], nullable: Seniority levels: Entry, Strategic, Senior, VP, CXO, Director, Manager, Partner, Owner
  - `companySize` string[], nullable: Company size: Self-employed, 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+
  - `industryId` string[], nullable: LinkedIn industry IDs of the person's current company, e.g. `["4", "96"]` (a single comma-separated entry like `["4,96"]` also works). Resolve IDs by name with GET /api/v1/enrichment/linkedin-industries. Max 70.
  - `excludeIndustryId` string[], nullable: LinkedIn industry IDs to exclude. Same format as industryId. Max 70.
  - `companyHeadquarterLocations` string[], nullable: Filter on where the person's current company is HEADQUARTERED (free-text location names, e.g. ["France"]). Distinct from locations/geoIds, which filter on where the person is. Max 70.
  - `excludeCompanyHeadquarterLocations` string[], nullable: Company headquarter locations to exclude. Max 70.
  - `page` integer: Page number (1-100). Default: 1. Each page returns up to 25 results.
  - `qualifiedOnly` boolean: When true, only return profiles with qualificationStatus=QUALIFIED. Disqualified results are dropped from the response (count and results shrink accordingly). Default false: return everything with the verdict flag set so the caller can decide.
  - `metadata` unknown[], nullable: Arbitrary pass-through array. Whatever you put here is echoed back verbatim and is NEVER used to filter the search. It is returned in the `metadata` field of the response (synchronous calls) and in every webhook payload (async calls — batch, each `per_result` POST, and failure callbacks alike). Use it to correlate responses with your own records: row IDs, campaign tags, source URLs, etc. Items may be strings or objects. Max 50 items, 10 KB serialized.
    - unknown
  - `webhookUrl` string, nullable: Optional. When supplied, the endpoint switches to async mode: it returns 202 Accepted immediately with a `requestId`, runs the search in the background, and POSTs the full response body to this URL once. Use when your client has a tight HTTP timeout (some serverless platforms, n8n defaults, etc.). When omitted, the endpoint stays synchronous and returns results in the same HTTP response.
  - `deliveryMode` string: Webhook delivery shape. Ignored when `webhookUrl` is omitted. `batch` (default) POSTs one payload containing every result. `per_result` POSTs one payload per result, each carrying `index` / `total` so the receiver can reassemble. Failed jobs always deliver one error payload regardless of mode; empty result sets emit no per-result POSTs (poll the GET endpoint to confirm completion).

## Response `200`

Synchronous result (no `webhookUrl` in the body).

- object: Typed response for /enrichment/people-search.
  - `data` object, nullable: People search payload, or null if none found
    - `results` object[], nullable: Matching profiles (up to 25 per page)
      - `linkedinUrl` string, nullable: Profile URL
      - `firstName` string, nullable: First name
      - `lastName` string, nullable: Last name
      - `location` string, nullable: Location string
      - `openProfile` boolean, nullable: True if the profile is an Open Profile (messageable without connection)
      - `premium` boolean, nullable: True if the member has a premium account
      - `currentPositions` object[], nullable: Current positions held by the person
        - `companyName` string, nullable: Company name
        - `title` string, nullable: Job title at the company
        - `companyLinkedinUrl` string, nullable: Company LinkedIn page URL
        - `startedOnYear` integer, nullable: Year the person started this position
        - `startedOnMonth` integer, nullable: Month (1-12) the person started this position
      - `qualificationStatus` string, nullable: AI qualification verdict, one of: QUALIFIED, DISQUALIFIED
      - `qualificationReason` string, nullable: Human-readable explanation for the qualification verdict
    - `count` integer, nullable: Number of results on this page
    - `page` integer, nullable: Current page number (1-based)
    - `totalPages` integer, nullable: Total number of pages available
    - `total` integer, nullable: Total number of matching profiles
    - `hasMore` boolean, nullable: True if more pages are available
    - `aiValidationStatus` string, nullable: AI qualification pass status, one of: ok (normal), unavailable (AI call failed; every result is defaulted to QUALIFIED)
    - `metadata` object[], nullable: Caller-supplied metadata echoed back for this request
      - `rowId` string, nullable: Caller-supplied row identifier echoed back for this request
      - `campaign` string, nullable: Caller-supplied campaign identifier echoed back for this request
  - `requestId` string, nullable: Unique request identifier

## Other responses

- `202`: Accepted for async processing — `webhookUrl` was provided.
- `422`: Validation Error
- `429`: Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.

---

[API](https://skmtc.dev/rodz/apis/rodz-api.md) · [All operations](https://skmtc.dev/rodz/apis/rodz-api/llms.txt) · [OpenAPI document](https://skmtc.dev/rodz/apis/rodz-api/revisions/3003505ff896?raw)
