Lugares · POST /v1/places/search
Búsqueda
Encuentra lugares según lo que son y dónde están. Una búsqueda responde al instante con los lugares que tenemos guardados, y recopila el resto cuando no bastan.
Haz una búsqueda
Una búsqueda necesita dos cosas: qué son los lugares, en keywords, y dónde están, en geo. Todo lo demás tiene un valor por defecto. Esta pide hasta 50 panaderías en Curitiba con calificación de 4 o más:
curl -X POST https://api.gmaps.dev/v1/places/search \
-H "Authorization: Bearer $GMAPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["panadería"],
"geo": { "location": "Curitiba, PR" },
"minRating": 4,
"limit": 50
}'| Campo | Por defecto | Qué hace |
|---|---|---|
keywords | Obligatorio | Qué buscar, como ["panadería"]. Cada término se busca por separado. Las mayúsculas, los acentos y los espacios de más no importan. |
geo | Obligatorio | Dónde buscar: exactamente una de las cuatro formas de abajo. |
lang | "pt" | El idioma de la búsqueda, en dos letras, como en. Los lugares que recopilamos para ti llegan en ese idioma. Cada idioma se busca por separado, así que una zona buscada en pt sigue siendo new en en. |
minRating | null | Deja solo los lugares con una calificación igual o mayor que esta, de 1 a 5. Los lugares que nadie ha calificado también quedan fuera. Con null, llegan todos. |
limit | 20 | Cuántos lugares quieres, de 1 a 120. También es lo máximo que puede costar la búsqueda, en créditos. |
wait | 0 | Cuántos segundos retiene la respuesta mientras llegan lugares nuevos, hasta 60. Con 0, la respuesta llega al instante. |
Un campo que no conocemos se rechaza, así que un error de tipeo nunca pasa inadvertido.
Indica dónde
geo acepta exactamente una de estas formas. Si envías dos, o mezclas sus campos, se rechaza.
| Forma | Qué cubre |
|---|---|
{ "location": "Curitiba, PR" } | Una ciudad de Brasil y su estado, en dos letras. Curitiba/PR y Curitiba - PR también funcionan, y también un nombre que solo tiene una ciudad. Buscamos a una distancia fija alrededor del centro de la ciudad. |
{ "lat": -25.4296, "lng": -49.2713, "radiusM": 1500 } | Un punto y hasta dónde buscar a su alrededor, en metros. Funciona en cualquier lugar del mundo. |
{ "bbox": [-49.31, -25.46, -49.23, -25.39] } | Un rectángulo, dado como oeste, sur, este y norte, en grados. El oeste debe ser menor que el este, y el sur menor que el norte. Una zona que cruza la línea de 180° se envía como dos rectángulos. |
{ "cityIbge": 4106902, "radiusKm": 8 } | Una ciudad de Brasil por su código IBGE de siete dígitos (el de Curitiba es 4106902) y hasta dónde buscar desde su centro, en kilómetros. |
location siempre cubre la misma distancia, que puede no llegar al borde de una ciudad grande. Para elegir el tamaño, envía cityIbge con radiusKm, o un punto con radiusM.
location solo encuentra ciudades de Brasil. Cuando no podemos saber a cuál te refieres, la búsqueda se rechaza con 422 GEO_UNRESOLVED:
- Varias ciudades tienen ese nombre: agrega el estado, como
Bom Jesus, PI.details.candidateslista las que encontramos. - Ninguna ciudad tiene ese nombre: revisa cómo lo escribiste. Si alguna se le parece, el mensaje pregunta si te referías a ella y
details.candidatesla lista. - El lugar está fuera de Brasil: envía un punto o un rectángulo.
Un código IBGE que no es de una ciudad de Brasil se rechaza de la misma manera.
Zonas demasiado grandes para una búsqueda
Buscamos una zona en cuadros pequeños, una vez por cada término, y Cobertura explica cómo. Algunas solicitudes son demasiado grandes para una sola búsqueda. Se rechazan con 400 VALIDATION_ERROR antes de que empiece nada:
- un radio mayor que el límite para una zona;
- una zona y unos términos que suman más cuadros de los que acepta una solicitud;
- más términos de los que acepta una solicitud.
El mensaje indica el límite y lo que enviaste. Usa una zona más pequeña o menos términos, o divide la solicitud en varias búsquedas.
Lee la respuesta
Esta es la respuesta para una zona que habíamos buscado en parte, recortada a un lugar y unos pocos campos:
{
"data": {
"places": [
{
"id": "5b0c8e0a-2f4d-4c1e-9a57-3d2b8f6e1c90",
"identity": {
"cid": "12345678901234567890",
"name": "Padaria Estrela do Centro",
"category": "Padaria",
"mapsUrl": "https://maps.google.com/?cid=12345678901234567890"
},
"ratings": { "rating": 4.6, "reviewCount": 212 },
"meta": { "cached": true }
}
],
"coverage": "partial",
"placesKnown": 14,
"collection": {
"id": "8c1f5e2a-7b3d-4f60-9e14-2a6d0b9c7f31",
"kind": "search",
"status": "queued",
"squaresTotal": 21,
"squaresCovered": 9,
"counts": {
"placesDelivered": 14,
"placesFresh": 0,
"placesCached": 14,
"creditsCharged": 0,
"creditsRefunded": 0
}
},
"collectionError": null
}
}places: hastalimitlugares, cada uno con la forma que describe Lugares. Si hay una recopilación, son los lugares que lleva hasta ahora, y los que ya teníamos guardados van primero. Si no, van primero los que tienen más reseñas.coverage: cuánto de la zona habíamos buscado hace poco.freshes toda la zona,partiales una parte ynewes nada.placesKnown: cuántos lugares teníamos guardados en la parte que habíamos buscado, contando solo los que cumplenminRating. Todos son gratis.collection: la recopilación que busca el resto, onullcuando no hizo falta recopilar nada. Recopilaciones lo explica todo.collectionError: por qué no pudo empezar una recopilación, onull.meta.cached, en cada lugar:truecuando ya lo teníamos guardado, así que no costó nada.
Cuando aún no tenemos suficientes lugares guardados
Una búsqueda inicia una recopilación solo cuando se cumplen las dos cosas: parte de la zona no se ha buscado hace poco, y tenemos menos de limit lugares guardados ahí. Si buscamos toda la zona hace poco, recibes lo que encontramos entonces, y no empieza nada.
La recopilación te entrega como máximo limit lugares, y los que ya teníamos guardados cuentan para ese número sin costo. Cada lugar nuevo cuesta 1 crédito cuando llega, así que una búsqueda nunca cuesta más de limit créditos. Iniciarla es gratis: toda búsqueda responde con x-request-cost: 0, y counts.creditsCharged de la recopilación muestra lo que ha cobrado desde entonces.
Si envías la misma búsqueda mientras su recopilación sigue en curso, recibes esa misma recopilación. No empieza una segunda ni cuesta más.
Para recibir los lugares nuevos, puedes:
- repetir la misma búsqueda más tarde. Los lugares nuevos llegan junto con los demás, y ahora son gratis.
- leer la recopilación en
GET /v1/collections/{id}, o seguir su progreso en vivo. - enviar
wait, como muestra la siguiente sección.
Espera los lugares nuevos
Con wait, la respuesta se retiene hasta que la recopilación termine o se acaben los segundos, lo que ocurra primero. Luego responde con los lugares que la recopilación lleva hasta ese momento. Cuando no hay nada que recopilar, responde al instante.
En el SDK, una llamada con wait recibe la espera completa, más un margen para que llegue la respuesta, aunque el timeout del cliente sea menor:
curl -X POST https://api.gmaps.dev/v1/places/search \
-H "Authorization: Bearer $GMAPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["panadería"],
"geo": { "location": "Curitiba, PR" },
"wait": 60
}'Para esperar más de 60 segundos, sigue el progreso en vivo de la recopilación.
Cuando una recopilación no puede empezar
Si se te acabaron los créditos, o ya tienes tantas recopilaciones en curso como permite tu plan, la búsqueda igual responde con los lugares que tenemos guardados. collection es null y collectionError dice por qué. Así termina una respuesta de ese tipo:
{
"collection": null,
"collectionError": {
"code": "QUOTA_EXCEEDED",
"message": "You reached your daily limit of 250 credits. Retry after midnight UTC. Buying credits does not raise this limit.",
"messageKey": "serverErrors.quotaDay",
"params": { "limit": 250 },
"details": {
"scope": "day",
"limit": 250,
"resetAt": "2026-09-25T00:00:00.000Z",
"retryAfterSecs": 3600
}
}
}El código siempre es QUOTA_EXCEEDED, y messageKey distingue los tres motivos:
serverErrors.quotaDay: llegaste al límite de hoy. Se reinicia a la medianoche UTC, y los créditos comprados no lo aumentan.serverErrors.quotaMonth: usaste los créditos de este mes y los de cualquier paquete de créditos. Los créditos de tu plan vuelven el día 1 a la medianoche UTC, o compra un paquete de créditos ahora.serverErrors.concurrency: ya tienes tantas recopilaciones en curso como permite tu plan. Intenta de nuevo cuando termine una.
La búsqueda en sí termina bien. Los números de cada plan están en Límites.
Cuando se rechaza una búsqueda
Una búsqueda rechazada no inicia nada y no cuesta nada. La respuesta dice por qué:
| Estado HTTP | Código | Motivo | Qué hacer |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Falta un campo, un valor está fuera de rango o hay un campo desconocido, geo tiene más de una forma, o la zona es demasiado grande. | Lee message y details, corrige el campo y envíala de nuevo. |
| 422 | GEO_UNRESOLVED | No podemos saber a qué ciudad de Brasil se refiere location, o el código IBGE no es de una ciudad. | Agrega el estado, corrige el código, o envía un punto o un rectángulo. |
| 429 | RATE_LIMIT_EXCEEDED | Demasiadas llamadas en este minuto. | Espera los segundos indicados en retry-after y envíala de nuevo. |
Una clave que falta o es incorrecta se rechaza como describe Autenticación. Quedarte sin créditos nunca hace que se rechace una búsqueda. Errores lista todos los códigos.