# Search People

> Search the people database. One call uses one page of the daily search budget.

Requires an API key with the `read` scope.

Each call fetches one page and counts against the workspace's daily search budget. The budget grows with the reveals you make that day; [Get Credits](/api-reference/lead-finder/get-credits) shows today's usage. Emails are not included in search results: reveal them with [Reveal Emails](/api-reference/lead-finder/reveal-emails). It needs a paid plan. `filters` is an object of filter keys. Call [Get Filter Options](/api-reference/lead-finder/get-filter-options) for the full list of keys and the allowed values for industries and company types. A value outside the provider's vocabulary matches nothing and returns zero rows rather than an error.

## Body Parameters

<ParamField body="filters" type="object" required>
  Person filters, for example `{"jobTitles": ["CTO"], "countries": ["US"]}`. At least one filter besides `countries` is required. `companyIds` accepts at most 200 entries.
</ParamField>

<ParamField body="pageSize" type="integer" default="25">
  Results per page, 1 to 50.
</ParamField>

<ParamField body="pageToken" type="string">
  The `nextPageToken` from the previous page.
</ParamField>

## Response

<ResponseField name="data" type="object">
  One page of results.

  <Expandable title="data">
    <ResponseField name="total" type="integer">Matching people across all pages.</ResponseField>
    <ResponseField name="people" type="array">
      The page.

      <Expandable title="people">
        <ResponseField name="id" type="string">Person identifier. Pass it to [Reveal Emails](/api-reference/lead-finder/reveal-emails).</ResponseField>
        <ResponseField name="firstName" type="string">First name.</ResponseField>
        <ResponseField name="lastName" type="string">Last name.</ResponseField>
        <ResponseField name="title" type="string">Current job title.</ResponseField>
        <ResponseField name="company" type="string">Current company.</ResponseField>
        <ResponseField name="companyDomain" type="string">Company domain.</ResponseField>
        <ResponseField name="linkedinUrl" type="string">LinkedIn profile URL.</ResponseField>
        <ResponseField name="location" type="string">Location.</ResponseField>
        <ResponseField name="industry" type="string">Industry.</ResponseField>
        <ResponseField name="companySize" type="integer">Company headcount, or `null` when unknown.</ResponseField>
        <ResponseField name="headline" type="string">Profile headline.</ResponseField>
        <ResponseField name="revealStatus" type="string">`pending` or `found` when this workspace has already revealed the person, otherwise `null`.</ResponseField>
        <ResponseField name="revealedEmail" type="string">The revealed email, once found.</ResponseField>
        <ResponseField name="inLeads" type="boolean">An active Lead exists for the revealed email right now.</ResponseField>
        <ResponseField name="leadId" type="string">That Lead's identifier, or `null`.</ResponseField>
      </Expandable>
    </ResponseField>
    <ResponseField name="nextPageToken" type="string">Pass as `pageToken` for the next page. `null` on the last page.</ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
```bash cURL
curl -X POST "https://api.foxreach.io/api/v1/lead-finder/search" \
  -H "X-API-Key: otr_your_key" \
  -H "Content-Type: application/json" \
  -d '{"filters": {"jobTitles": ["CTO"], "countries": ["US"]}, "pageSize": 25}'
```

```python Python SDK (beta)
from foxreach import FoxReach

client = FoxReach(api_key="otr_your_key")
page = client.lead_finder.search({"jobTitles": ["CTO"], "countries": ["US"]}, page_size=25)
```

```typescript TypeScript SDK (beta)
import { FoxReach } from "foxreach";

const client = new FoxReach({ apiKey: "otr_your_key" });
const page = await client.leadFinder.search({
  filters: { jobTitles: ["CTO"], countries: ["US"] },
  pageSize: 25,
});
```
</RequestExample>

<ResponseExample>
```json
{
  "data": {
    "total": 18240,
    "people": [
      {
        "id": "per_abc123",
        "firstName": "Jane",
        "lastName": "Doe",
        "title": "CTO",
        "company": "Acme Inc",
        "companyDomain": "acme.com",
        "linkedinUrl": "https://www.linkedin.com/in/janedoe",
        "location": "Austin, Texas, United States",
        "industry": "Computer Software",
        "companySize": 120,
        "headline": "CTO at Acme",
        "revealStatus": null,
        "revealedEmail": null,
        "inLeads": false,
        "leadId": null
      }
    ],
    "nextPageToken": "eyJwIjoyfQ"
  }
}
```
</ResponseExample>

## Errors

| Status | Description |
|--------|-------------|
| `401` | Missing, invalid, revoked or expired API key |
| `403` | API key does not have the required scope: `read` |
| `400` | `country_not_available` when a requested country is outside the covered list (`{"detail": {"code": "country_not_available", "message": "...", "allowed": [], "blocked": []}}`); `unknown_filter_keys` naming each key that does not exist (`{"detail": {"code": "unknown_filter_keys", "message": "...", "unknownKeys": [], "validKeys": []}}`); or a message asking for at least one filter besides `countries` |
| `403` | `upgrade_required` on the Free plan: `{"detail": {"code": "upgrade_required", "limit_type": "lead_finder", "message": "..."}}`. A missing scope also returns 403 with a plain `detail` string |
| `404` | `Lead Finder is not enabled` while Lead Finder is switched off on this environment |
| `422` | More than 200 `companyIds` in one call (`too_many_company_ids`), or `pageSize` outside 1-50 |
| `429` | `lead_finder_search_cap` when today's search budget is used up: `{"detail": {"code": "lead_finder_search_cap", "message": "...", "used": 20, "allowance": 20, "revealsToday": 0}}`. Revealing emails raises the allowance, or retry tomorrow |
| `502` | `The data provider is unavailable right now` |
| `503` | `Lead Finder is not configured` when it is enabled but has no data provider key |

## Rate Limit

- **100 requests per minute, per API key.** Fixed 60-second window.
- Every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (unix epoch seconds).
- A `429` response includes a `Retry-After` header (seconds until the bucket resets).

For client-side patterns (`Retry-After`, exponential backoff, monitoring `X-RateLimit-Remaining`), see [Rate Limiting](/rate-limiting).
