---
title: "Search Local Leads"
method: POST
path: "/v3/local-leads/search"
tags: ["Local Leads"]
---

# Search Local Leads

`POST /v3/local-leads/search`

## Request

- Base URL: `https://api.leadmagic.io`
- URL: `https://api.leadmagic.io/v3/local-leads/search`
- Auth: API key in header `X-API-Key`

Search 59 million local business listings by location, category, name or map radius.
Each lead is the full listing: address, coordinates, phones, emails, website and socials.

Pages hold **25 leads** and the size is fixed: `limit`, `offset` and `page` return 400.
Page with `next_cursor`. A search holds up to 1,000 leads for 30 minutes.

**Zero credits** on Professional (5 requests/second) and Ultimate (10 requests/second),
within the fair-use ceilings of 10 million records/month and 13,333 searches/day shared
across People, Company, Jobs and Local Leads Search. Other plans pay **1 credit per page**
at 5 requests/second. A page that is read again within 30 minutes is not charged again.

Every search needs a `country`, a point (`lat` and `lon`), a `website_domain`,
`email_domain` or `email`, or a `name` of five or more characters.

## Request body

- object
  - `country` union: Two-letter country code. Up to 5 per search.
    - string
    - string[]
  - `region_code` union: State or region code, such as TX. Alias region. Needs country.
    - string
    - string[]
  - `city` union: City name. Needs country.
    - string
    - string[]
  - `postal_code` union: Postal code. A 5-digit US ZIP also matches ZIP+4 listings. Needs country.
    - string
    - string[]
  - `street` string: Text contained in the street address. Needs country.
  - `category` union: Exact category name, from GET /v3/local-leads/categories.
    - string
    - string[]
  - `category_contains` union: Text contained in the category name. roof matches roofing.
    - string
    - string[]
  - `category_group` union: Broader category group, such as food_and_drink.
    - string
    - string[]
  - `kind` union: business, civic or place.
    - string
    - string[]
  - `name` string: Text contained in the business name.
  - `website_domain` union: Website host. A bare host, a www. host or a URL. Alias domain.
    - string
    - string[]
  - `email_domain` union: Domain of an email on the listing.
    - string
    - string[]
  - `email` string: An exact email address on the listing.
  - `phone` string: A phone number in any format, 7 to 15 digits. Needs country.
  - `has_email` boolean
  - `has_business_email` boolean: An email on the business's own domain, not a free mailbox.
  - `has_phone` boolean
  - `has_website` boolean
  - `has_social` boolean
  - `is_chain` boolean
  - `min_confidence` number
  - `confidence_tier` union: high or medium.
    - string
    - string[]
  - `operating_status` union: open, unknown, temporarily_closed or permanently_closed.
    - string
    - string[]
  - `exclude_closed` boolean: True keeps open and unknown listings only.
  - `lat` number: Latitude of a point search. Send with lon. Results are nearest first.
  - `lon` number: Longitude of a point search. Send with lat.
  - `radius_m` integer: Radius of a point search, in metres.
  - `sort` 'confidence' | 'name': Not allowed with a point search.
  - `cursor` string: next_cursor from the previous page, sent with the same filters.

## Response `200`

One page of local leads (flat JSON body: not wrapped in data)

- object
  - `message` string, required
  - `credits_consumed` number, required: 0 on Professional and Ultimate, and 0 when the page was already paid for
  - `credits_previously_consumed` number: Present when the page was first read by an earlier request
  - `leads` object[], required
    - `id` string: Stable listing id. Use it to remove duplicates.
    - `name` string
    - `kind` 'business' | 'civic' | 'place'
    - `is_chain` boolean
    - `category` string
    - `category_group` string
    - `categories` string[]
    - `category_inferred` boolean: True when the category was read from the business name.
    - `street` string
    - `city` string
    - `region` string
    - `region_code` string
    - `postal_code` string
    - `country` string
    - `lat` number
    - `lon` number
    - `distance_m` number: Metres from the point. Point searches only.
    - `filled` string[]: Address fields filled in from neighbouring listings.
    - `phone` string, nullable
    - `phones` string[]
    - `email` string, nullable
    - `emails` string[]
    - `email_domain` string
    - `website` string, nullable
    - `website_domain` string
    - `socials` string[]
    - `has_email` boolean
    - `has_phone` boolean
    - `has_website` boolean
    - `has_social` boolean
    - `has_business_email` boolean
    - `confidence` number: 0 to 1
    - `confidence_tier` 'high' | 'medium'
    - `operating_status` 'open' | 'unknown' | 'temporarily_closed' | 'permanently_closed'
  - `count` integer, required: Leads in this page
  - `page_size` integer, required: Always 25
  - `total` integer, nullable: Every listing the search matches; null when the count did not finish in time
  - `has_more` boolean, required: More pages remain in the stored result list
  - `next_cursor` string, nullable: Send back as cursor for the next page; null on the last page
  - `has_more_beyond_snapshot` boolean: The search matches more than the 1,000 leads it holds
  - `snapshot_limit_reached` boolean: This is the last page of the 1,000 and more listings exist
  - `interpreted_search` object: The filters as they were applied
  - `metadata` object
    - `query_name` string
    - `pagination` string
    - `snapshot_id` string
    - `snapshot_page_start` integer
    - `snapshot_cache_status` 'cold' | 'hit'

## Other responses

- `400`: Bad Request - The request was malformed or contains invalid parameters. **Common causes:** - Missing required fields - Invalid field format (e.g., malformed email) - Invalid JSON syntax - Invalid parameter values
- `401`: Unauthorized - Authentication failed. **Common causes:** - Missing X-API-Key header - Invalid or expired API key - Malformed API key
- `402`: Payment Required - The request can't be paid for. Check `code`: - `insufficient_credits`: add credits at https://app.leadmagic.io/settings/billing - `credits_frozen`: credits are temporarily unavailable; contact support@leadmagic.io - `org_closed`: the key is valid but the subscription has ended. Resubscribe at https://app.leadmagic.io/settings/billing, then retry with the same key. Retrying without resubscribing won't help, and repeated retries return `429` with `Retry-After`.
- `410`: The cursor expired (restart_required) or the search is past its 1,000 leads (snapshot_limit_reached)
- `429`: Too Many Requests - Rate limit exceeded. **Action required:** Check the `Retry-After` header for when to retry. Also returned when the same rejected API key (`401 invalid_api_key` or `402 org_closed`) is retried 10 or more times within 10 minutes. The key is paused for 15 minutes, then 1 hour, then 24 hours if retries continue. Fix the key or resubscribe instead of retrying. **Headers returned:** - `Retry-After`: Seconds until you can retry - `RateLimit-Limit`: Your limit per minute - `RateLimit-Remaining`: Remaining requests this minute - `RateLimit-Reset`: Seconds until limit resets
- `503`: Service Unavailable - The service is temporarily unavailable. **Action required:** Retry after a brief delay.

## Changes

- **2026-11-12** `1ae235c25bcc`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/leadmagic/apis/leadmagic-api/changes/v3/local-leads/search/post.md)

---

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