API
Last updated: September 2, 2026
Every failure uses one envelope with a stable
code. Branch on the code, not on the status or the
message. Statuses are conventional and messages are written for humans and may
be reworded; codes are part of the contract.
{"error": {
"code": "lead_limit_reached",
"message": "This cycle's lead allowance is spent: 4,812 of 5,000 used.",
"field": "total_limit",
"details": {"leads_used": 4812, "lead_limit": 5000},
"request_id": "req_..."
}}field names the offending input when one is to blame.details carries whatever is useful to act on, such as the
suggestions for an unrecognised category or the figures behind a quota
rejection.request_id is worth logging. Quote it to us and we can find
the exact request.| Code | Status | What to do |
|---|---|---|
invalid_api_key | 401 | Check the header and the key. Do not retry with the same value. |
key_revoked | 401 | Create a new key in Settings. |
key_expired | 401 | Create a new key. |
insufficient_scope | 403 | The key lacks the scope named in details. |
api_not_available_on_plan | 403 | API access is on the Scale plan. |
api_disabled | 503 | The API is temporarily off. Retry after the interval given. |
| Code | Status | What to do |
|---|---|---|
validation_error | 422 | The body failed schema validation. field names the culprit. Unknown fields are rejected, so check for a typo. |
unsupported_query | 400 | Not a Google Maps category. Use the suggestions, or search /categories. |
unknown_regions | 400 | A region name was not recognised. Use full names, not abbreviations. |
missing_region | 400 | No valid region was supplied. |
missing_location | 400 | Give either states or cities. |
unresolvable_cities | 400 | None of the named cities exist in our index. |
unsupported_country | 400 | Use one of us, au, uk, ca. |
too_many_queries | 400 | Up to three categories per job. |
too_many_cities | 400 | Up to fifty cities per job. |
invalid_total_limit | 400 | total_limit must be a positive number of rows. |
total_limit_exceeds_max | 400 | Above your per-scrape ceiling. Split the job. |
invalid_max_emails_per_company | 400 | Must be 1 or more, or omitted entirely. |
invalid_cursor | 400 | Pass a next_cursor from a previous page, or omit it. |
client_forbidden | 403 | This key cannot use that client_id. See /clients. |
| Code | Status | What to do |
|---|---|---|
lead_limit_reached | 402 | This cycle's allowance is spent. It resets on your billing date. |
org_past_due | 402 | Payment failed, so new scrapes are paused. Existing results still download. |
org_cancelled | 403 | Subscription cancelled. Resume it in billing. |
org_blocked | 403 | The workspace is suspended. Contact us. |
queue_depth_exceeded | 409 | Too many scrapes already waiting. Let one start first. |
| Code | Status | What to do |
|---|---|---|
job_not_found | 404 | No such job in this workspace. |
job_not_complete | 409 | The scrape has not finished, so no file exists yet. |
download_not_available | 404 | That format or scope does not exist for this job. Check the job's downloads flags. |
job_not_cancellable | 409 | Already finished. |
download_unavailable | 503 | Could not mint a link. Retry. |
| Code | Status | What to do |
|---|---|---|
idempotency_key_reuse | 409 | That key was used with a different body. Use a new key. |
request_in_progress | 409 | A request with that key is still being processed. Retry shortly. |
rate_limited | 429 | Back off for Retry-After seconds. |
Limits are per minute, in fixed windows.
| Scope | Limit | Applies to |
|---|---|---|
| Per key | 120 / min | Every request |
| Per workspace | 300 / min | Every request, across all your keys |
| Submissions | 10 / min | POST /jobs only |
An idempotent replay does not count against the submission limit, because it creates nothing. There is also an edge limit in front of everything, so a runaway loop may be refused before it reaches the application at all.
Every response carries your current position:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1788387840X-RateLimit-Reset is a Unix timestamp for when the window rolls
over. On a 429 you also get Retry-After in seconds,
computed from that boundary rather than being a flat minute, so honouring it
resumes as early as possible.
Retry-After, then use exponential backoff with jitter.Idempotency-Key on every submission you might retry.
It is the difference between a retry and a duplicate scrape.Create a free MapsData account and get 500 Google Maps leads with emails every month. No card needed.
Get 500 free leads a month