API

Polling and lifecycle

Last updated: September 2, 2026

A scrape is a background job, not a request you wait on. Submitting returns immediately with a job id, and the work happens on our scraping fleet. How long that takes depends far more on how much of the target area we have seen recently than on the size of the job, so plan for a range rather than a number.

States

queued -> running -> completed -> failed -> cancelling -> cancelled
StatusMeaning
queuedAccepted, waiting for a free worker.
runningBeing scraped. progress and lead_count move.
completedFinished. Files are ready to download.
failedSomething went wrong. error_message says what. Partial results are often still exported and are not billed.
cancellingCancel requested, worker is winding down.
cancelledStopped. Leads already delivered are still billed.

How long it takes

Minutes to several hours. The dominant factor is how many business websites in the target area we have to visit for the first time to extract an email; areas we have covered recently finish far faster than fresh ones. A job's own row count matters much less than that.

This means you should not build a timeout that assumes a small job is a fast job. Watch the status, not the clock.

Polling, sensibly

Poll at an interval measured in minutes, not seconds. Once a minute is plenty for a job that will run for an hour, and the rate limit will stop a tight loop anyway. A reasonable pattern is to start at roughly max(60, total_limit / 200) seconds and back off from there.

GET /api/v1/jobs/8f2c... {"id": "8f2c...", "status": "running", "progress": 42, "lead_count": 210, "email_count": 0, "stop_reason": null, "downloads": {...}}
You do not have to poll at all. MapsData emails the workspace when a scrape finishes. If your integration can wait for a person, that is often the simpler design.

Reading the numbers

  • progress is a percentage, and it is an estimate. It can sit still while a slow area is worked through.
  • lead_count is rows scraped so far, and moves during the run.
  • email_count is rows carrying a deliverable email. It is set when the job settles, and it is the figure your allowance is billed on.
  • stop_reason says why the scrape stopped. It is set on essentially every completed scrape, so treat it as informational rather than as a problem signal, and compare it against specific values rather than testing whether it is present.
stop_reasonWhat happenedShort result?
limit_reachedIt scraped the total_limit you asked for. The ordinary outcome.No
coverage_exhaustedIt searched every area you selected and that was all there was. Re-running the same search returns the same count. Widen the region, or add cities.Expected
diminishing_returnsFurther calls would mostly have repeated businesses already found, so it stopped. A healthy outcome, not a failure.Expected
barren_queryThe densest areas returned almost nothing, so there was no market to keep walking toward. Usually means the category is genuinely rare in that region.Expected
user_cancelSomeone cancelled it. Leads already delivered are still billed.Yes
stallIt stopped making progress and was ended rather than left hanging. Retrying is reasonable.Yes
memory_checkpointA very large scrape was checkpointed and recycled mid-run. Internal housekeeping.Sometimes
nullNo reason was recorded. Read it alongside status: a cancelled or failed run can stop before one is set, and older scrapes predate the field.Sometimes

The last three are rare. stall and memory_checkpoint exist so that an unusual ending is still explained rather than silent, and neither has occurred on a customer scrape to date.

A short result is usually not a failure. Three of these mean the area simply did not contain that many businesses in your category, and re-running the same search will return the same count. Check stop_reason before treating a scrape as having underdelivered, and before retrying it.

Listing scrapes

Newest first, cursor paginated. Pass the previous page's next_cursor to continue. Do not build page numbers; the cursor is stable even when new jobs arrive mid-pagination.

GET /api/v1/jobs?limit=25 GET /api/v1/jobs?limit=25&cursor=<next_cursor> GET /api/v1/jobs?status=running

Downloading

Check the downloads object on the job to see which files exist, then ask for a link. The flags and the download endpoint always agree: if a flag is false, that file genuinely does not exist and asking for it returns 404 rather than quietly handing you a different one.

GET /api/v1/jobs/8f2c.../download?format=csv&scope=emails {"url": "https://...", "expires_at": "2026-09-02T22:45:00Z", "format": "csv", "scope": "emails", "filename": "Plumber.csv"}
ParameterValuesMeaning
formatcsv, xlsxFile type. Defaults to csv.
scopeemailsRows with a deliverable email. The default, and what you are billed on.
allEvery scraped row, email or not.
filteredOutput of a filter run, if one exists.

Links expire after fifteen minutes. Fetch the file promptly, and request a new link rather than caching the URL. We return the link as JSON rather than redirecting to it, because a redirect to storage makes some HTTP clients resend your Authorization header to a third-party host.

Cancelling

POST /api/v1/jobs/8f2c.../cancel

A queued scrape stops for free. Cancelling a running scrape still bills the leads already delivered, the same as in the dashboard, so it is not a way to undo a submission. A job that has already finished returns 409 job_not_cancellable.

Try it on your own market

Create a free MapsData account and get 500 Google Maps leads with emails every month. No card needed.

Get 500 free leads a month
MapsData © 2026 Hiive Arts Home Pricing Privacy Policy Terms of Service