---
title: "Search the contact database (free, masked results)"
method: POST
path: "/lead-finder/searches"
tags: ["Lead Finder"]
---

# Search the contact database (free, masked results)

`POST /lead-finder/searches`

## Request

- Base URL: `https://api.emailchaser.com/r`
- URL: `https://api.emailchaser.com/r/lead-finder/searches`
- Auth: HTTP bearer

Searches Emailchaser's B2B contact database with explicit filters and returns one page of matching people, masked: first name, last initial, title, seniority, job function, company name, industry, size and revenue band, a company logo (logoUrl, an image this API serves, whose URL does not contain the company's domain), and city, state and country. No email address, email or company domain, LinkedIn URL or phone number is ever returned: contact details are revealed only by adding people to a campaign with POST /lead-finder/imports. Searching spends no credits, but every result row counts against the account's daily browsing allowance (limits.rowsPerDay in GET /lead-finder/filters, 2,000 rows a UTC day by default and 250 on a trial; rowsLeftToday shows what is left). An account may start 20 searches a minute and have 6 underway at once; a search started past that is refused with rate_limited (reason searches_running) and a Retry-After of a few seconds, and nothing is spent. Searches that find nobody also draw on a bucket of 120 that refills at one every 30 seconds; while it is empty, every new search is refused with rate_limited (reason empty_searches) until the next refill, usually within 30 seconds. The same page asked for again within 10 minutes comes from cache and spends nothing. The request waits up to about six seconds: 200 means the search finished (status done, or failed with error saying why, for example rate_limited when the shared request budget or the search queue is busy, which is worth asking again after a few seconds), 202 means it is still running, so read it with GET /lead-finder/searches/{id} using the returned searchId. total is exact when totalIsExact is true; otherwise it is a lower bound until totalStatus is done. inWorkspace marks people Lead Finder added to this workspace whose lead is still there, so adding them again would be skipped for free. Each person's ref stays valid for 60 minutes after the page it came on was last shown. A read-only key may call this endpoint.

## Request body

- ModelsLeadFinderSearchRequest
  - `filters` ModelsLeadFinderFilterSet
    - `cities` string[]
    - `companyKeywords` string: CompanyKeywords is one phrase matched against what the employer does.
    - `companyName` string: CompanyName is one phrase matched against the employer's name.
    - `companySizes` string[]: CompanySizes are headcount bands from GET /lead-finder/filters.
    - `continents` string[]
    - `countries` string[]: Countries, Regions and Continents are values from GET /lead-finder/filters, where the person is. Use one of the three at a time.
    - `domains` string[]: Domains and ExcludeDomains are company domains, up to 1,000 each.
    - `excludeCountries` string[]
    - `excludeDomains` string[]
    - `excludeHeadquartersCountries` string[]
    - `excludeIndustries` string[]
    - `excludeJobTitles` string[]
    - `headquartersCountries` string[]: HeadquartersCountries are where the employer is headquartered.
    - `industries` string[]: Industries are values from GET /lead-finder/filters.
    - `jobFunctions` string[]: JobFunctions are values from GET /lead-finder/filters.
    - `jobTitles` string[]: JobTitles are free text, matched as OR terms.
    - `regions` string[]
    - `revenue` string[]: Revenue is revenue bands from GET /lead-finder/filters.
    - `seniorities` string[]: Seniorities are values from GET /lead-finder/filters.
    - `states` string[]: States and Cities are free text, matched inside the person's location.
    - `technologies` string[]: Technologies are free text: tools the employer uses.
  - `page` integer: Page is 1-based, up to limits.maxPage. Defaults to 1.
  - `pageSize` integer: PageSize is 25 (the default) or 50.

## Response `200`

Search finished (status done or failed)

- ModelsLeadFinderSearch
  - `audienceKey` string: AudienceKey names the filters: the same picks in any order give the same key. Imports from these filters carry it too.
  - `creditsPerProspect` integer
  - `error` string: Error is set on a failed search: rate_limited, provider_blocked, provider_unavailable (the people database is down or in maintenance; try again later), timeout, invalid_filters, budget_exhausted, expired or internal.
  - `hasMore` boolean
  - `maxPage` integer
  - `message` string
  - `page` integer
  - `pageSize` integer
  - `progress` ModelsLeadFinderProgress
    - `added` integer: Added is how many people they added.
    - `adds` integer: Adds is how many imports there were, selected ones included.
    - `lastAddAt` string: LastAddAt is when the latest import from these filters started.
    - `nextFrom` integer: NextFrom is the position in the results (1 is the first person) the next first_n import of these filters starts from.
    - `runningImportId` integer: RunningImportID is a first_n import of these filters still running. Another first_n import of the same filters is refused (409 import_running) until it ends.
  - `results` ModelsLeadFinderPerson[]: Results are the people on this page, masked.
    - `company` ModelsLeadFinderPersonCompany
      - `industry` string
      - `logoUrl` string: LogoURL is the company's icon, an image of at most 64 pixels served by this API with no key needed. The URL does not contain the company's domain. It is left out when the company has no website on record, and answers 404 when the website has no icon.
      - `name` string
      - `revenueBand` string
      - `sizeBand` string
    - `firstName` string
    - `inWorkspace` boolean: InWorkspace is true for someone Lead Finder added to this workspace whose lead is still there, so adding them again is skipped for free. A person who is a lead from another source shows false; adding them is still skipped and costs nothing.
    - `jobFunction` string
    - `lastInitial` string
    - `location` ModelsLeadFinderPersonLocation
      - `city` string
      - `country` string
      - `state` string
    - `ref` string: Ref identifies the person for POST /lead-finder/imports. It stays valid for 60 minutes after the page it came on was last shown.
    - `seniority` string
    - `title` string
  - `rowsLeftToday` integer: RowsLeftToday is the account's browsing allowance left this UTC day.
  - `searchId` string
  - `status` string: Status is running, done or failed.
  - `total` integer: Total is how many people match; TotalIsExact says whether it is a count or a lower bound, and TotalStatus whether the count has landed (pending, done or failed).
  - `totalIsExact` boolean
  - `totalStatus` string

## Other responses

- `202`: Search still running: read it with GET /lead-finder/searches/{id}
- `400`: invalid_filters (field, value and reason name the problem) or invalid_request (page or pageSize)
- `401`: Unauthorized - invalid or missing API key
- `403`: plan_required: the workspace's plan does not include Lead Finder
- `409`: provider_unavailable: the contact database is switched off
- `429`: rate_limited (reason searches_per_minute, searches_running, empty_searches or daily_preview_limit) or budget_exhausted (reason daily_budget, monthly_budget or fair_use_floor): retry after retryAfterSeconds, also sent as a Retry-After header
- `500`: internal

---

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