# Search Companies

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

Requires an API key with the `read` scope.

A company page costs the same as a people page and counts against the same daily search budget. It needs a paid plan. Company filters have their own keys; see `companyFilterKeys` in [Get Filter Options](/api-reference/lead-finder/get-filter-options).

## Body Parameters

<ParamField body="filters" type="object" required>
  Company filters. At least one filter besides `countries` is required.
</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 companies across all pages.</ResponseField>
    <ResponseField name="companies" type="array">
      The page.

      <Expandable title="companies">
        <ResponseField name="id" type="string">Company identifier.</ResponseField>
        <ResponseField name="name" type="string">Company name.</ResponseField>
        <ResponseField name="domain" type="string">Domain.</ResponseField>
        <ResponseField name="linkedinId" type="string">LinkedIn public id.</ResponseField>
        <ResponseField name="linkedinUrl" type="string">LinkedIn company URL.</ResponseField>
        <ResponseField name="logoUrl" type="string">Logo URL.</ResponseField>
        <ResponseField name="description" type="string">Description.</ResponseField>
        <ResponseField name="location" type="string">Headquarters location.</ResponseField>
        <ResponseField name="industry" type="string">Industry.</ResponseField>
        <ResponseField name="type" type="string">Company type.</ResponseField>
        <ResponseField name="employees" type="integer">Headcount.</ResponseField>
        <ResponseField name="employeeRange" type="string">Headcount range.</ResponseField>
        <ResponseField name="revenueRange" type="string">Revenue range.</ResponseField>
        <ResponseField name="growth12m" type="integer">12-month headcount growth, percent.</ResponseField>
        <ResponseField name="specialties" type="array">Listed specialties.</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/companies/search" \
  -H "X-API-Key: otr_your_key" \
  -H "Content-Type: application/json" \
  -d '{"filters": {"industries": ["Computer Software"], "minHeadcount": 50}, "pageSize": 25}'
```

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

client = FoxReach(api_key="otr_your_key")
page = client.lead_finder.search_companies({"industries": ["Computer Software"], "minHeadcount": 50})
```

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

const client = new FoxReach({ apiKey: "otr_your_key" });
const page = await client.leadFinder.companiesSearch({
  filters: { industries: ["Computer Software"], minHeadcount: 50 },
});
```
</RequestExample>

<ResponseExample>
```json
{
  "data": {
    "total": 4120,
    "companies": [
      {
        "id": "co_abc123",
        "name": "Acme Inc",
        "domain": "acme.com",
        "linkedinId": "acme",
        "linkedinUrl": "https://www.linkedin.com/company/acme",
        "logoUrl": null,
        "description": "Acme makes scheduling software.",
        "location": "Austin, Texas, United States",
        "industry": "Computer Software",
        "type": "Privately Held",
        "employees": 120,
        "employeeRange": "51-200",
        "revenueRange": null,
        "growth12m": 18,
        "specialties": ["Scheduling"]
      }
    ],
    "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` | `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).
