Skip to content

Collections

Collections

A collection searches a whole area, not just one page of results. Get a free quote, start it, then read the places as they arrive.

When you need one

A search gives you up to 120 places. A whole city has far more businesses than that, so a collection splits the area into small squares and searches each one, once for every term. It runs in the background: a few minutes for a small area, longer for a city.

Squares that anyone searched for the same term and language in the last 180 days are already saved. Their places come back at once and cost nothing. A square that came back with no places counts for only 7 days, and then we search it again. You pay 1 credit for each new place we find for you.

What you send

The first four fields work as they do in a search. The last two belong to collections. A quote and a collection take the same body:

FieldWhat it does
keywordsWhat to look for, such as ["bakery"]. At least one. We search every square once per term, so each extra term makes the collection take longer. Repeats are dropped, and one collection takes a limited number: past it, the answer is 400 VALIDATION_ERROR with the limit in details.limit.
geoWhere to look, in exactly one of four shapes: a Brazilian city, a point and a radius, a box, or a city's IBGE code and a radius. Search shows each one.
langTwo letters for the language to search in, such as en. New places come back in it. It's pt unless you set it.
minRatingKeep only places rated at least this, from 1 to 5. Leave it out to keep every place.
maxPlacesThe most places the collection hands you, so also the most new places you pay for. Unless you set it, it's the most your plan allows.
enrichAdd ["emails"] to look for email addresses too. See Emails.

A large area with many terms can come to more squares than one collection takes. Then the answer is 400 VALIDATION_ERROR: use a smaller area or fewer terms, and try again.

Get a quote first

A quote tells you what a collection would cost before you start it. It's free, and it starts nothing:

curl -X POST https://api.gmaps.dev/v1/collections/quote \
  -H "Authorization: Bearer $GMAPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["bakery"],
    "geo": { "location": "Curitiba, PR" },
    "maxPlaces": 500
  }'

Here's the answer, without sample:

{
  "data": {
    "coverage": "partial",
    "squaresTotal": 21,
    "squaresCovered": 9,
    "squaresToSearch": 12,
    "placesKnown": 140,
    "maxCost": 360
  }
}
  • coverage: how much of the area we searched recently. fresh is all of it, partial is some, and new is none.
  • squaresTotal, squaresCovered, squaresToSearch: the squares the area comes to, counted once per term. Covered ones answer at once. Each one still to search takes a few minutes.
  • placesKnown: how many places we already saved there. They're free.
  • maxCost: the most it can cost, in credits. That's maxPlaces minus the places we already have, or twice that when you ask for emails. It usually costs less, because nobody knows how many businesses a square holds until we search it.
  • sample: a few of the places we already have, so you can see what's there.

A quote checks your terms, the size of the area, maxPlaces and emails the same way starting a collection does. If the quote refuses, starting would too.

Start it

Send the same body to start the collection. The answer comes at once, with status 202: we accepted it, and the searching goes on in the background.

curl -X POST https://api.gmaps.dev/v1/collections \
  -H "Authorization: Bearer $GMAPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["bakery"],
    "geo": { "location": "Curitiba, PR" },
    "maxPlaces": 500
  }'

What comes back is the collection itself:

{
  "data": {
    "id": "8c1f5e2a-7b3d-4f60-9e14-2a6d0b9c7f31",
    "kind": "collection",
    "status": "queued",
    "stopReason": null,
    "query": {
      "keywords": ["bakery"],
      "geo": { "location": "Curitiba, PR" },
      "lang": "pt",
      "minRating": null,
      "maxPlaces": 500,
      "enrich": []
    },
    "area": { "lat": -25.4195, "lng": -49.2646, "radiusM": 10000 },
    "squaresTotal": 21,
    "squaresCovered": 9,
    "jobsTotal": 12,
    "jobsDone": 0,
    "counts": {
      "placesDelivered": 140,
      "placesFresh": 0,
      "placesCached": 140,
      "creditsCharged": 0,
      "creditsRefunded": 0
    },
    "error": null,
    "queuedAt": "2026-09-24T14:02:11.000Z",
    "startedAt": null,
    "finishedAt": null,
    "cancelRequestedAt": null,
    "resultsExpireAt": "2026-10-24T14:02:11.000Z"
  }
}

The places we already saved are in it from the start. Here, counts.placesCached is 140.

When every square was already searched, there's nothing left to do. The collection comes back finished, with status succeeded, and it cost nothing.

Starting a collection is free. You pay as places arrive: we take the credits for new places first, then add them to your collection, and it never hands you more than maxPlaces:

  • 0A place we already saved comes back in the same answer, marked cached: true.
  • 1A new place that a collection finds for you.
  • 1Emails for a new place, on paid plans: 1 credit per place, only when we find at least one.
  • 0Searching, quotes, exports and checking your usage.
  • 0A collection that finds nothing.

Send the same request while it's still running and you get the same collection back. You don't start a second one, and you don't pay twice.

Before anything starts, we check two things. If either fails, the answer is 429 QUOTA_EXCEEDED:

  • details.scope is concurrency: you're already running as many collections as your plan allows. We don't hold the new one for later, so send it again once one ends, or cancel one first.
  • details.scope is day or month: you reached your daily credit limit or used this month's credits, and part of the area still needs searching. details.resetAt says when they come back. Credits you buy help with the month, not the day: the daily limit still applies.

How big and how many

Each plan sets the most places one collection hands you, and how many collections run at once:

PlanPlaces per collectionCollections at once
Free5001
Starter5,0002
Pro25,0005
Scale100,00010

Asking for more than your plan's maxPlaces answers 400 VALIDATION_ERROR. Your plan's other limits are on Limits, and you can change plans on the Plan page.

Follow it

Read the collection again whenever you want to know how far it got. It's free:

curl https://api.gmaps.dev/v1/collections/8c1f5e2a-7b3d-4f60-9e14-2a6d0b9c7f31 \
  -H "Authorization: Bearer $GMAPS_API_KEY"

To see places as they arrive, open its live progress. To have your server told when it ends, add a webhook.

jobsDone out of jobsTotal is how far along it is. We search the squares in batches, and each batch is one step.

statusWhat it means
queuedAccepted, waiting for its turn. Nothing is searched yet, but the places we already saved are in it.
runningSearching. New places arrive after each batch of squares.
succeededDone. It searched the whole area, or it stopped once it held your maxPlaces.
partialEnded before it searched the whole area or reached maxPlaces. stopReason says why. The places that arrived are yours.
failedNothing arrived, because we couldn't run the searches. error says so, and nothing was charged.
cancelledYou cancelled it.

When a collection stops before it has searched the whole area or reached maxPlaces, or ends with no places, stopReason says why:

stopReasonWhat it means for you
nullIt searched the whole area, or it reached your maxPlaces and left the rest of the area unsearched.
quotaThis month's credits ran out partway, so the rest of the area wasn't searched. Add credits on the Plan page or wait for the month to reset, then start the same collection again. The squares it already searched come back free.
daily_capYou reached your daily credit limit. It resets at midnight UTC: start the same collection again after that, and the squares it already searched come back free.
cancelledYou cancelled it. What arrived before that is yours.
engineA problem on our side stopped some of the searching. It's nothing you did. With partial, you keep what arrived. With failed, nothing was charged. Try again in a few minutes, and write to support if it keeps happening.
emptyIt found no places, so nothing was charged. That doesn't mean there are no businesses there. Try other terms, a bigger area or a lower minRating.

counts is what it handed you and what that cost:

  • placesDelivered: places in the collection. Always placesFresh plus placesCached.
  • placesFresh: new places, searched for the first time or again because our copy was more than 180 days old. 1 credit each.
  • placesCached: places we already saved. Free.
  • creditsCharged: 1 per new place, and 1 more when we found an email for it.
  • creditsRefunded: credits given back. A collection that ends with no places gives back everything it took.

queuedAt, startedAt and finishedAt say when it was accepted, when it started and when it ended.

List your collections

Your collections come newest first. Filter by status to find the ones still running. limit takes 1 to 100, and it's 20 unless you set it. offset skips ahead, and total says how many there are in all:

curl "https://api.gmaps.dev/v1/collections?status=running" \
  -H "Authorization: Bearer $GMAPS_API_KEY"

Cancel it

Cancel a collection you no longer want. What happens depends on how far it got:

curl -X DELETE https://api.gmaps.dev/v1/collections/8c1f5e2a-7b3d-4f60-9e14-2a6d0b9c7f31 \
  -H "Authorization: Bearer $GMAPS_API_KEY"
  • Waiting its turn: it stops at once, and it costs nothing.
  • Running: nothing new starts. The searches already under way finish, and their places are added and charged as usual. Then its status turns cancelled. cancelRequestedAt shows when you asked.
  • Already ended: there's nothing to stop. The answer is 409 CONFLICT, with its status in details.status, and its places stay where they are.

Read its places

The places come in the order they arrived, oldest first, so a page you already read stays the same while more arrive. limit takes 1 to 200, and it's 50 unless you set it:

curl "https://api.gmaps.dev/v1/collections/8c1f5e2a-7b3d-4f60-9e14-2a6d0b9c7f31/places?limit=200" \
  -H "Authorization: Bearer $GMAPS_API_KEY"

Each item is a full place. Its meta.cached is true when we already had it, so it was free. That's how you check what you paid for.

For the next page, add limit to offset. You've read them all when offset reaches total.

A page can hold fewer places than limit when a business asked us to leave it out, so don't stop at a short page. The collection's counts still include that place and what it cost.

How long its places stay

You can read a collection's places for 30 days after you start it, until resultsExpireAt. Then we delete its list of places and its live progress. The collection itself stays, with its counts and charges.

Once they're deleted, its places page comes back empty and an export is refused, so export what you want to keep before then. To get the places again, start the same collection: squares searched in the last 180 days come back free.