> ## 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 company search

> Starts a search for companies 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`. Every requirement is checked for each company, and only companies that match all of them are returned.

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

> [!WARNING]
>
> Starting a search spends credits as companies 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": "Privately held dental practices in Texas hiring SDRs",
  "limit": 20
}
```

```json Structured filters theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "filters": {
    "all": [
      {
        "field": "company.headquarters.country",
        "operator": "in",
        "value": ["US"]
      },
      {
        "field": "company.employee_count",
        "operator": "between",
        "value": [10, 200]
      },
      {
        "related": {
          "relationship": "open_jobs",
          "where": {
            "all": [
              {
                "field": "title",
                "operator": "in",
                "value": ["Sales Development Representative", "SDR"]
              }
            ]
          }
        }
      }
    ]
  },
  "criteria": ["independently owned, not part of a dental support organization"],
  "limit": 20,
  "max_credits": 25
}
```

```json With contacts theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "query": "Series B fintech companies in New York",
  "limit": 10,
  "persona_ids": ["c92d77d7-cc85-4a62-bcec-518b1d7d6260"]
}
```

### 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`

What 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 companies to return. The search stops when it has found this many.

Range: 1 to 500.

**persona\_ids** `string[]`

Personas to find contacts for at each matching company. Omitted or empty means no contact lookup and no contact charges. Personas choose which people to find; they do not filter which companies match.

At most 10 items.

**exclude\_domains** `string[]`

Company domains to skip, for example companies 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. |
| `403` | `permission_denied` | The workspace is not allowed to do this. `details` gives a reason, such as `contact_search_disabled` when `persona_ids` is sent and contact search is turned off. |
| `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/companies/search \
  -H "Authorization: Bearer $AVINA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "query": "Privately held dental practices in Texas hiring SDRs",
    "limit": 20
  }'
```

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

response = requests.post(
    "https://api.avina.io/v1/companies/search",
    headers={"Authorization": f"Bearer {os.environ['AVINA_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "query": "Privately held dental practices in Texas hiring SDRs",
      "limit": 20
    },
)
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/companies/search`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AVINA_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    "query": "Privately held dental practices in Texas hiring SDRs",
    "limit": 20
  }),
});
const data = await response.json();
console.log(data);
```

```json 202 theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "object": "company_search",
  "id": "32ba40da-e558-442a-8945-e93fc771afc9",
  "status": "queued",
  "stop_reason": null,
  "error": null,
  "query": "Privately held dental practices in Texas hiring SDRs",
  "limit": 20,
  "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:02:11Z",
  "completed_at": null,
  "expires_at": null,
  "status_url": "https://api.avina.io/v1/companies/search/32ba40da-e558-442a-8945-e93fc771afc9/status",
  "results_url": "https://api.avina.io/v1/companies/search/32ba40da-e558-442a-8945-e93fc771afc9/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.