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

# Start a people search

> Starts a search for people that match a natural-language `query`, or structured `filters` and `criteria`.

Returns `202` immediately with the search's `id`; the search runs in the background.

Send either `query`, or `filters` and/or `criteria`. Conditions on `person.*` fields describe the person; conditions on `company.*` fields describe their current employer. Only people who match every requirement are returned.

A search returns names, titles and LinkedIn profiles. Email addresses and phone numbers are looked up only when you set `enrich_emails` or `enrich_phones`, and cost extra.

Poll [`GET /people/search/{search_id}/status`](https://docs.data.avina.io/api-reference/people/get-search) and read people from [`GET /people/search/{search_id}/results`](https://docs.data.avina.io/api-reference/people/list-results) as they are found.

> [!WARNING]
>
> Starting a search spends credits as people are found. Reading status and results is free. Set `max_credits` to cap what one search can spend. See [Pricing](https://docs.data.avina.io/concepts/pricing.md).

### Example bodies

```json Natural language theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "query": "Heads of revenue operations at US fintech companies with 200 to 1,000 employees",
  "limit": 25,
  "enrich_emails": true
}
```

```json Structured filters theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "filters": {
    "all": [
      {
        "field": "person.title",
        "operator": "in",
        "value": ["VP Sales", "Head of Sales", "Chief Revenue Officer"]
      },
      {
        "field": "person.location.country",
        "operator": "in",
        "value": ["US"]
      },
      {
        "field": "company.industry",
        "operator": "in",
        "value": ["Software Development"]
      },
      {
        "field": "company.employee_count",
        "operator": "between",
        "value": [50, 500]
      }
    ]
  },
  "limit": 25,
  "enrich_emails": true,
  "max_credits": 20
}
```

### Headers

**Idempotency-Key** `string`

A unique string for this request, 1 to 255 characters. Retrying with the same key and body returns the original response instead of starting new work. Reusing a key with a different body returns `409 idempotency_key_reused`. Always send one when starting a search.

### Body

**query** `string`

Who to find, in plain language. Required unless you send `filters` or `criteria`. Cannot be combined with them.

Maximum 1,000 characters.

**filters** `object | null`

Structured conditions. A record must meet every condition in `all`. `null` is treated the same as leaving `filters` out. See the [filter reference](https://docs.data.avina.io/guides/structured-filters.md) for every field and operator.

**properties**

**all** `object[]` *required*

The conditions. A record must meet every one. Each item is a field condition (`field`, `operator`, `value`) or a `related` condition.

**item properties**

**field** `string`

The field to test, such as `company.industry` or `person.title`.

**operator** `string`

How to compare. Which operators a field accepts depends on its type.

Options: `in`, `matches`, `eq`, `gt`, `gte`, `lt`, `lte`, `between`, `within_last_days`.

**value** `any`

The value to compare against. A list for `in`, a two-item list for `between`, a `{amount, currency}` object for money fields, a number of days for `within_last_days`.

**related** `object`

A condition on records related to the company. All conditions in `where` must be true of the same record, for example one job listing.

**properties**

**relationship** `string` *required*

`open_jobs`: the company has at least one open job that matches. `new_hires`: someone with a matching title joined the company within the window.

**where** `object` *required*

Conditions on the related record.

**properties**

**all** `object[]` *required*

Conditions on `title` (`in`), `posted_at` (`within_last_days`, for `open_jobs`) or `started_at` (`within_last_days`, for `new_hires`).

**item properties**

**field** `string` *required*

The field on the related record.

Options: `title`, `posted_at`, `started_at`.

**operator** `string` *required*

`in` for `title`; `within_last_days` for `posted_at` and `started_at`.

**value** `any` *required*

A list of titles for `in`, or a whole number of days from 1 to 36500 for `within_last_days`.

**criteria** `(string | object)[] | null`

Free-text requirements, each checked against evidence for every candidate. Use them for anything the structured fields cannot express. Each item is a string, or an object with `text` and `kind`.

At most 10 items.

**item properties**

**text** `string` *required*

The requirement, written as a statement that is true of a match.

**kind** `string` (default: event)

`attribute`: a lasting fact the company's own description could state, such as "sells to hospitals". `event`: something that happened, such as "opened a location in Texas this year"; checked by web research.

**limit** `integer` (default: 20)

The most people to return. The search stops when it has found this many.

Range: 1 to 500.

**enrich\_emails** `boolean` (default: false)

Look up a work email address for each person found. Charged per person looked up. An email is not guaranteed.

**enrich\_phones** `boolean` (default: false)

Look up a phone number for each person found. Charged per person looked up, at a higher rate than email. A phone number is not guaranteed.

**exclude\_linkedin\_urls** `string[]`

LinkedIn profile URLs to skip, for example people you already have.

**max\_credits** `number`

The most credits this search may spend. 1 credit = \$1.00. When the search reaches it, it stops with `stop_reason` `usage_limit_reached` and keeps the results found so far. Defaults to your remaining balance.

### Response

**`202`** The search was accepted and queued.

**object** `string` *required*

`company_search` or `people_search`.

**id** `string` *required*

The search's identifier. Use it to read status and results.

**status** `string` *required*

`queued` and `running` are in progress. `completed`, `failed` and `cancelled` are terminal. `completed` means this run finished, not that every matching record in the world was found.

**stop\_reason** `string | null` *required*

Why a finished search stopped. `null` while it is in progress. Can also be `null` on a `failed` search; read `error`.

Options: `target_reached`, `sources_exhausted`, `usage_limit_reached`, `retrieval_limit_reached`, `query_needs_clarification`, `provider_failed`, `cancelled`.

**error** `string | null` *required*

A message when `status` is `failed`. Results found before the failure stay readable.

**query** `string | null` *required*

The natural-language request, when the search was started with `query`.

**limit** `integer` *required*

The most results this search will return.

**interpretation** `object | null` *required*

How a `query` was read. `null` until the query has been interpreted, and for searches started with `filters` or `criteria`.

**properties**

**filters** `object`

Structured conditions. A record must meet every condition in `all`. `null` is treated the same as leaving `filters` out. See the [filter reference](https://docs.data.avina.io/guides/structured-filters.md) for every field and operator.

**properties**

**all** `object[]` *required*

The conditions. A record must meet every one. Each item is a field condition (`field`, `operator`, `value`) or a `related` condition.

**item properties**

**field** `string`

The field to test, such as `company.industry` or `person.title`.

**operator** `string`

How to compare. Which operators a field accepts depends on its type.

Options: `in`, `matches`, `eq`, `gt`, `gte`, `lt`, `lte`, `between`, `within_last_days`.

**value** `any`

The value to compare against. A list for `in`, a two-item list for `between`, a `{amount, currency}` object for money fields, a number of days for `within_last_days`.

**related** `object`

A condition on records related to the company. All conditions in `where` must be true of the same record, for example one job listing.

**properties**

**relationship** `string` *required*

`open_jobs`: the company has at least one open job that matches. `new_hires`: someone with a matching title joined the company within the window.

**where** `object` *required*

Conditions on the related record.

**properties**

**all** `object[]` *required*

Conditions on `title` (`in`), `posted_at` (`within_last_days`, for `open_jobs`) or `started_at` (`within_last_days`, for `new_hires`).

**item properties**

**field** `string` *required*

The field on the related record.

Options: `title`, `posted_at`, `started_at`.

**operator** `string` *required*

`in` for `title`; `within_last_days` for `posted_at` and `started_at`.

**value** `any` *required*

A list of titles for `in`, or a whole number of days from 1 to 36500 for `within_last_days`.

**criteria** `object[]`

Free-text requirements read from the query.

**item properties**

**text** `string` *required*

The requirement, written as a statement that is true of a match.

**kind** `string`

`attribute`: a lasting fact the company's own description could state, such as "sells to hospitals". `event`: something that happened, such as "opened a location in Texas this year"; checked by web research.

**unsupported\_criteria** `string[]`

Requirements no public source can confirm, quoted from the query. A search cannot run while there are any.

**errors** `object[]`

Problems validating the filters the query was read as. A search cannot run while there are any.

**item properties**

**field** `string`

The filter path with the problem.

**message** `string` *required*

What is wrong.

**assumptions** `object[]` *required*

Ambiguous wording in the query and how it was read.

**item properties**

**text** `string` *required*

The exact phrase from the query.

**assumed** `string` *required*

The reading that was used.

**alternatives** `string[]` *required*

Other readings. Reword the query if one of these is what you meant.

**progress** `object` *required*

Counts so far. They only increase.

**properties**

**candidates** `integer` *required*

Candidates checked so far.

**accepted** `integer` *required*

Candidates that matched every requirement and were added to the results.

**rejected** `integer` *required*

Candidates that failed at least one requirement.

**unknown** `integer` *required*

Candidates whose evidence could not confirm every requirement. They are not returned.

**not\_returned** `integer` *required*

Candidates that matched every requirement but were not returned because `limit` or a spend limit had already been reached.

**contacts\_found** `integer` *required*

Contacts found so far. For company searches with `persona_ids`, and people searches with enrichment.

**credits\_charged** `number` *required*

Credits charged for this search so far. 1 credit = \$1.00.

**cancel\_requested** `boolean` *required*

`true` after a cancel request, until the search reaches `cancelled`.

**created\_at** `string` *required*

When the search was started.

**completed\_at** `string | null` *required*

When the search reached a terminal status.

**expires\_at** `string | null` *required*

When the search and its results stop being readable. `null` when no expiry is set.

**status\_url** `string` *required*

The URL of this search's status.

**results\_url** `string` *required*

The URL of this search's results.

### Errors

| Status | Code | When |
| - | - | - |
| `400` | `invalid_request` | The request is invalid. `details` names each problem. |
| `401` | `invalid_api_key` | The API key is missing, invalid or revoked. |
| `402` | `usage_limit_reached` | The workspace has no credits left. Nothing was started or charged. |
| `409` | `idempotency_key_reused` | The `Idempotency-Key` was already used with a different request, or its first request is still running. |
| `429` | `rate_limited` | Too many requests. Retry after `Retry-After` seconds. |
| `500` | `internal_error` | Something went wrong on our side. Retry with backoff, and with the same `Idempotency-Key` if you sent one. |

Every error uses the same shape. See [Errors](https://docs.data.avina.io/api-reference/errors.md).

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.avina.io/v1/people/search \
  -H "Authorization: Bearer $AVINA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "query": "Heads of revenue operations at US fintech companies with 200 to 1,000 employees",
    "limit": 25,
    "enrich_emails": true
  }'
```

```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import os
import uuid
import requests

response = requests.post(
    "https://api.avina.io/v1/people/search",
    headers={"Authorization": f"Bearer {os.environ['AVINA_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "query": "Heads of revenue operations at US fintech companies with 200 to 1,000 employees",
      "limit": 25,
      "enrich_emails": True
    },
)
response.raise_for_status()
print(response.json())
```

```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch(`https://api.avina.io/v1/people/search`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AVINA_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    "query": "Heads of revenue operations at US fintech companies with 200 to 1,000 employees",
    "limit": 25,
    "enrich_emails": true
  }),
});
const data = await response.json();
console.log(data);
```

```json 202 theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "object": "people_search",
  "id": "7c1d9a52-3e0b-4f6a-9d21-5b8e4a7c0f13",
  "status": "queued",
  "stop_reason": null,
  "error": null,
  "query": "Heads of revenue operations at US fintech companies with 200 to 1,000 employees",
  "limit": 25,
  "interpretation": null,
  "assumptions": [],
  "progress": {
    "candidates": 0,
    "accepted": 0,
    "rejected": 0,
    "unknown": 0,
    "not_returned": 0,
    "contacts_found": 0
  },
  "credits_charged": 0,
  "cancel_requested": false,
  "created_at": "2026-11-12T17:10:02Z",
  "completed_at": null,
  "expires_at": null,
  "status_url": "https://api.avina.io/v1/people/search/7c1d9a52-3e0b-4f6a-9d21-5b8e4a7c0f13/status",
  "results_url": "https://api.avina.io/v1/people/search/7c1d9a52-3e0b-4f6a-9d21-5b8e4a7c0f13/results"
}
```

```json 400 theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "code": "invalid_request",
    "message": "filters.all.0: unknown field 'company.size'",
    "request_id": "req_8f2a61c09d4e7b3a5f10c2d8",
    "details": [
      {
        "field": "filters.all.0",
        "message": "unknown field 'company.size'; supported fields are listed in the filter reference"
      }
    ]
  }
}
```


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