---
title: "Search whole areas with the grid, as a job (SPENDS TOKENS)"
method: POST
path: "/api/v1/searches"
---

# Search whole areas with the grid, as a job (SPENDS TOKENS)

`POST /api/v1/searches`

## Request

- Base URL: `https://lyreleads.com`
- URL: `https://lyreleads.com/api/v1/searches`
- Auth: HTTP bearer

The search the Search page runs. mode "grid" lays a grid of points across each area and densifies where it keeps finding new businesses, which is the method that found 1,061 roofing contractors in Houston where paging deeper from one centre found 255. mode "city" pages from each area's centre and is cheaper for small towns.

Areas are "Houston, Texas", {name, state}, or an id from GET /api/v1/areas. A name that fits more than one place (the US area list has 13 Springfields, and "Houston" alone could be in Texas, Missouri, Mississippi or Alaska) is never guessed: the whole request returns 400 with ambiguous[].candidates, each carrying an id, label, population and coordinates, and nothing is charged. Resend with the id you mean. An unknown name returns 400 with suggestions. Size a grid first with POST /api/v1/searches/estimate.

One lead per NEW listing; listings you already hold cost nothing, ever, and fetching pages carries a small per-page minimum. Areas your account already covers for this query are skipped. At most 2 searches run at once per account, and re-sending an identical search while it runs returns the running job instead of starting a second.

Returns job_id immediately. Poll GET /api/v1/searches/{id}, or subscribe a webhook to job.completed. Read the rows with GET /api/v1/searches/{id}/results. Every new business is enriched automatically as it lands.

## Request body

- object
  - `query` string, required
  - `country` string, required: As listed by GET /api/v1/areas.
  - `areas` union[], required
    - union
      - string: "Name, State", a plain name that only one place carries, or an id from GET /api/v1/areas
      - object
        - `id` string: From GET /api/v1/areas or ambiguous[].candidates. Takes precedence over name.
        - `name` string
        - `state` string
        - `pages` integer: city mode only: pages per area, 1-10. Omit for 1.
  - `mode` 'grid' | 'city'

## Response `200`

job_id, mode, status_url, results_url. Or fullyCovered: true with no job, when every area is already covered for this query.

## Other responses

- `400`: Missing fields, unknown areas (unknown[] with suggestions), or names that fit more than one place (ambiguous[] with candidates and ids)
- `402`: Insufficient leads
- `429`: Two searches already running, or rate limit

---

[API](https://skmtc.dev/lyreleads/apis/lyre-leads-api.md) · [All operations](https://skmtc.dev/lyreleads/apis/lyre-leads-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lyreleads/apis/lyre-leads-api/revisions/1c7c73cc355f?raw)
