Scrapes
Create scrape
Order a scrape: find businesses live on Google Maps and deliver them as leads.
api.leadity.io/v1/scrapesspendSpends creditsMCP tool create_scrapeTakes credits: orders a scrape that searches Google Maps live in the selected areas and delivers up to targetLeads businesses as leads, holding their price up front. Price it first with estimate_scrape, which is free and answers the per-lead rate, the account's floors and how much of the selection is still unswept. The hold is ceil(targetLeads x leadRateMilli / 1000) credits for the leads and, when review scraping is ordered, ceil(targetLeads x maxReviews x review) credits beside it, review being the per-review rate get_pricing names: each part is rounded up to a whole credit on its own, so set maxCredits to the two together. estimate_scrape answers the per-lead rate and never the reviews part, and a quote_exceeded refusal charges nothing and names the whole hold in credits. Whatever the run does not deliver is refunded when it settles, and a business the account already holds, in any niche, is skipped and never charged. The call answers at once and the scrape runs for minutes to hours: watch it with get_scrape_status every 30 to 60 seconds, never faster, until complete is true, then read the leads with list_leads or download_leads. Needs a key with the spend scope. A refusal names its reason in error, for example below_minimum, all_covered, insufficient_credits or quote_exceeded.
Headers
Bearer, a space, then an API key: Bearer lk_api_... An MCP key is refused here with wrong_key_kind.
Your own key for this one purchase. Send the same key again to retry it safely: the retry replays the first answer instead of charging twice, and carries Idempotent-Replayed: true. The same key on a different request answers idempotency_conflict, and a spend without one answers idempotency_key_required.
16 to 64 characters, matches ^[A-Za-z0-9_-]+$.
application/json
Body parameters
One to ten niche ids from list_niches. The plan draws across them at random.
1 to 10 items, each 1 to 100 characters.
Where to search: whole regions, single ZIP or postal codes, or both. A code already swept for a niche is skipped for that niche.
Show child attributesHide child attributes
Whole regions (a state, province, territory or UK region), every area in each. list_territories names them.
At most 200 items.
Show child attributesHide child attributes
The two-letter country code, e.g. US. list_territories names the countries on sale.
Matches ^[A-Z]{2}$.
Single ZIP or postal codes. list_areas and search_areas name them.
At most 60,000 items.
Show child attributesHide child attributes
The two-letter country code, e.g. US. list_territories names the countries on sale.
Matches ^[A-Z]{2}$.
The region the code sits in, when known.
1 to 8 characters.
One ZIP or postal code exactly as list_areas names it, e.g. 78701.
1 to 16 characters.
The delivery filters, each independent of the others. app-api validates this object, so a bad value answers invalid_body. Today: websitePresence (required: any, has or none); phoneTypeFilter (off, with_phone, mobile, landline or voip); findOwner (true delivers only businesses with a confirmed owner name); emailFinder (off, require or require_verified, which deliver only businesses whose own site publishes an address, verified for the second; stepped down to off when websitePresence is none); nicheMatch (true delivers only businesses whose own Google main category is an ordered niche); minGoogleReviews (0 or one of the floors get_pricing lists); reviews ({ minReviews, maxReviews }: walk each business's Google reviews, charged per review). Absent fields are off. The full and current list, with prices, is on the filters page of the Leadity docs; get_scrape_defaults answers the account's own usual set.
How many leads to deliver at most. At least the minTargetLeads estimate_scrape answers.
At most 1,000,000, greater than 0.
A name for the scrape. Left out, one is derived from its niches and areas.
At most 100 characters.
The most this call may take, in whole credits. If the price is higher nothing is charged and the call answers quote_exceeded.
At most 100,000,000, greater than 0.
Response
The new scrape's id. Pass it to get_scrape_status to watch it.
reserving, queued and running are live; stopping and settling are finishing; completed is final.
One ofreservingqueuedrunningstoppingsettlingcompleted
Distinct codes the plan searches.
Searches the plan runs.
The price of the leads, held now.
The review-scraping hold beside it. 0 when none was ordered.
The email filter the scrape really runs, after the no-website step-down.
True when this idempotency key had already placed the order: nothing new was charged, and this is that order.
Errors
Every refusal answers { error, message } with the status below. The full list is on the Errors page.
| Code | Status | Meaning | Extra fields |
|---|---|---|---|
| unauthorized | 401 | The API key is missing, malformed, revoked or expired. | - |
| wrong_key_kind | 401 | This key opens the other surface: an API key works on the HTTP API, an MCP key on the MCP server. | - |
| insufficient_scope | 403 | The key does not carry the scope this operation needs. | requiredScope: The scope the operation needs: read, write or spend. |
| account_suspended | 403 | The account is suspended. | - |
| email_not_verified | 403 | The account's email address is not verified yet. | - |
| invalid_body | 400 | The request does not match the operation's schema. | issues: The problems found, each with path (the field as a dotted path, led by the part of the request it travels in: path, query or body, such as body.items.1) and message (what is wrong there). |
| package_locked | 402 | Until its first purchase the account may order only the starter packages. The body names what was ordered and what is allowed. | ordered: The package the order's filters read as, custom for any other set.allowed: The packages the account may order now. |
| insufficient_credits | 402 | The balance does not cover the price. Nothing was charged. | required: On create_validation: the credits the list holds. |
| quote_exceeded | 409 | The price is above the maxCredits the call allowed. Nothing was charged. | credits: What the call would have taken: the whole hold on an order or a list, the price or the hold on an upgrade.maxCredits: The ceiling the call sent.reviewsReservedCredits: On create_scrape: the part of credits held for review scraping.count: On purchase_phone_reveal, when the count was the cause: how many numbers the reveal would name.maxNumbers: On purchase_phone_reveal, when the count was the cause: the maxNumbers the call sent. |
| idempotency_key_required | 400 | A spending operation must carry an Idempotency-Key header (16 to 64 characters of A-Z, a-z, 0-9, _ and -). | - |
| invalid_idempotency_key | 400 | The Idempotency-Key must be 16 to 64 characters of A-Z, a-z, 0-9, _ and -. | - |
| idempotency_conflict | 409 | This Idempotency-Key was already used for a different request. | - |
| below_minimum | 400 | The quantity is under the smallest one this operation takes: targetLeads (the body carries min), or an upgrade's target (list_scrape_offers names it). | min: On create_scrape: the smallest targetLeads the account may order. |
| all_covered | 409 | Every area selected is already swept for these niches. Choose other areas. | - |
| rate_limited | 429 | Too many requests. Wait for the Retry-After seconds and try again. | retryAfterSeconds: The seconds to wait, the same number as the Retry-After header. |
| try_again | 503 | Leadity could not answer just now. Retry in a moment, with the same Idempotency-Key on a spending call. | retryAfterSeconds: When a request with this Idempotency-Key is still being processed: the seconds to wait before retrying with the same key, as the Retry-After header says. |
| internal_error | 500 | Something failed on our side. Nothing was charged twice. | body: On the MCP server, when Leadity answered in a shape the tool does not publish: that answer as it came. |