Reference

API

Agent-first structured business data from public Google Maps listings

One request

curl -s https://mapcensus.com/v1/scrape \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'content-type: application/json' \
  -d '{"query":"coffee shops","location":"Austin, TX","limit":10}'

Paying

Two ways. An API key spends a credit balance. Or send no key at all: the response is 402 with a machine-readable price for that request, and a client that speaks the x402 payment flow signs an authorization for it and retries. That payment buys that request and nothing more - no balance is kept for a caller with no account. It is charged the quoted price when it returns at least one row. A request that returns no rows is not charged; the payment can be presented again to retry that same request, up to 3 attempts in all, within 6 minutes of the first. It buys an answer in the same response: POST /v1/jobs needs an account, and a request that outlives its response is stopped, not charged. To pay once for many calls, add credit to an account with POST /v1/credits, which needs one.

Credits are atomic units of the settlement asset: 1,000,000 credits = $1. Billing is per record, added up from the lines that apply - at the free rate a listing row is $4.00 per thousand and a detailed place $6.00 per thousand. Three cheaper rates are opened by a monthly plan, and rows stay pay-as-you-go on every one of them - a plan buys the rate and never comes with credit. A cached answer costs 10% of a fresh one. The whole card, every unit at every rate: /pricing for a person, /v1/pricing for a program. GET /v1/account reports which rate a key is on, and when it renews.

Depth

listing reads the results feed: name, category, rating, review count. Fast and cheap, because one page load yields many rows. detail opens each place - hours, phone, website, address parts, price band, photos, booking links, the menu, the busyness curve, tickets, room rates, the owner's posts, the verdict on the area, and the places shown alongside. One page load per place, so it costs proportionally more.

Fields

GroupHolds
identityBusiness name, category list, and the listing’s stable identifiers.
locationFull address broken into parts, plus latitude, longitude and plus code.
ratingAverage rating, total review count, and the one-to-five star distribution.
contactPublic phone number and website.
hoursOpening hours per day, and whether a place has closed temporarily or for good.
busynessThe published hour-by-hour busyness curve, and how busy the place is right now.
pricePrice band and, where published, an estimated spend per person.
menuThe published menu where there is one: sections, dish names, prices and descriptions.
mediaThe listing's cover photo, and the names of the photo tabs it groups the rest under.
actionsReservation, ordering and menu links the listing offers.
reviewsIndividual reviews with rating, text, date and any per-category scores the reviewer gave, plus the aggregate topic tags.
attributesAmenities and descriptors exactly as the listing publishes them, grouped into the sections the source groups them into and each carrying whether the place offers it.
ticketsAdmission and experience tickets on sale, each with a price in USD, its seller and a booking link.
hotelFor a place that takes room bookings: star rating, the dates quoted, every rate offered, and the nearby hotels shown beside it.
postsUpdates the owner has published, with the event date and time any of them carries. What the owner says, which is not the same as what is currently true.
areaThe published verdict on the surrounding area: an overall visitor score, and the transit, sightseeing and airport scores behind it.
webPages elsewhere on the web that cite this place, each with its provider and the snippet it was shown under.
relatedThe places shown alongside this one, with rating and review count - the competitive set as the source itself draws it.

Ask for fewer and the response is smaller and faster. The default is identity, location, rating, contact, hours - every group that carries no separate charge. Naming any others adds them; "fields": "all" asks for the lot. Every field lists what is inside each group, column by column, with what it costs.

One group returns personal data. reviews carries the display name a reviewer published alongside what they wrote, so asking for it makes you a controller of that data in your own right - with your own transparency and rights obligations, separately from ours. The terms set this out and the privacy notice describes what we drop before it reaches you. If the question is about a business rather than about the people who reviewed it, rating gives you the score and the count without any of this.

Size and shape

POST /v1/scrape answers inside the request, up to 60 results. Beyond that use POST /v1/jobs, poll GET /v1/jobs/{id}, then fetch GET /v1/jobs/{id}/results. A job and its results are kept for 7 days, then deleted - and an Idempotency-Key is remembered for as long as its job is, so a key sent again after that starts a new request.

Ask for ?format=ndjson for anything large: it streams a row at a time, so neither side has to hold the whole result. csv and json are also available.

A row comes in one of two shapes. The default, ?shape=flat, is a single snake_case level - place_id, review_count - which is what a spreadsheet wants and what CSV can express. ?shape=nested returns the record as the crawler itself holds it, with the sections and spelling it uses - identifiers.placeId, rating.reviewsCount - so a pipeline already reading those records needs no translation table. It is the shape on disk, so ?format=ndjson&shape=nested&fields=all is served with no parsing at all, and it is the cheapest way to take delivery of a large result. There is no nested CSV, and asking for one is an error rather than a flat file you did not ask for.

Speed and cost

Set max_age_seconds to the oldest answer you would accept. The same question already answered inside that window returns in milliseconds from cache and is billed at the cache rate. When freshness does not matter, this is the single biggest lever on both latency and price.

The cache is keyed on what you asked about, not on how much of it you wanted: limit, fields and max_age_seconds do not split it. So a request for ten rows is served from an answer someone already crawled fifty of, at the cache rate - while a request for fifty is not served from an answer of ten, because that would be a short answer pretending to be a complete one.

Limits

Requests per minute (per key)120
Requests per minute (unauthenticated, per address)60
Concurrent jobs per account3
Max results per job5,000
Max reviews per place200

Errors

Every error is the same shape: a stable error code, a message for a human, and a request_id to quote. Branch on the code; the wording may change.

{
  "error": "insufficient_credits",
  "message": "…",
  "request_id": "a1b2c3d4e5"
}

Machine-readable

/openapi.json · Model Context Protocol