Places API

The Places API provides hybrid text and geographic search across the Geog places database. Built on a geo-composite cell file architecture using H3 cell partitioning for efficient spatial queries.

Base URL

https://api.geog.dev/v1/places

Authentication

Places API requests require authentication via Bearer token:

curl -X POST "https://api.geog.dev/v1/places/search" \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"location": {"lat": 37.7749, "lon": -122.4194}, "radius": 5000}'

Endpoints

1. Search Places

Search for places using text queries, geographic constraints, and category filters.

POST/v1/places/search

Request Body

ParameterTypeRequiredDefaultDescription
locationobjectYes-Geographic center point: { "lat": number, "lon": number }
radiusnumberNo5000Search radius in meters (1-100,000)
querystringNo-Text search query (e.g., "coffee shops")
categoriesstring[]No-Filter by categories: ["restaurant", "cafe"]
limitintegerNo20Results per page (1-1,000)
offsetintegerNo0Pagination offset
weightsobjectNo-Hybrid scoring weights: { "text": 0.6, "geo": 0.4 }

Location constraints:

  • lat: Latitude (-90 to 90)
  • lon: Longitude (-180 to 180)

Weights object:

  • text: Weight for text relevance scoring (0-1)
  • geo: Weight for geographic proximity scoring (0-1)

Example Request

curl -X POST "https://api.geog.dev/v1/places/search" \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "coffee shop",
    "location": { "lat": 37.7749, "lon": -122.4194 },
    "radius": 5000,
    "limit": 5
  }'

Example Response

{
  "results": [
    {
      "id": "8529a1003ffffff_n456789012",
      "score": 0.95,
      "name": "Blue Bottle Coffee",
      "category": "cafe",
      "categories": ["cafe", "coffee_shop"],
      "location": {
        "lat": 37.7849,
        "lon": -122.4088
      },
      "distance": 1250,
      "address": "66 Mint St, San Francisco, CA 94103",
      "city": "San Francisco",
      "region": "California",
      "postcode": "94103",
      "phone": "+14158438220",
      "website": "https://bluebottlecoffee.com",
      "brand": "Blue Bottle Coffee",
      "sourceId": "way/123456789",
      "confidence": 0.98,
      "updatedAt": "2025-11-20T08:00:00Z",
      "scores": {
        "text": 0.92,
        "geo": 0.98
      }
    }
  ],
  "total": 245,
  "executionTime": 42,
  "queryStats": {
    "pruningEfficiency": 0.85,
    "cellsSearched": 3
  }
}

Response Fields

FieldTypeDescription
resultsarrayArray of matching places
results[].idstringUnique place identifier
results[].scorenumberCombined relevance score (0-1)
results[].namestringPlace name
results[].descriptionstringPlace description (when available)
results[].categorystringPrimary place category
results[].categoriesarrayAll categories for this place
results[].tagsarrayTags associated with this place
results[].locationobjectGeographic coordinates (lat, lon)
results[].distancenumberDistance from search center (meters)
results[].addressstringStreet address
results[].citystringCity name
results[].regionstringState or region name
results[].postcodestringPostal code
results[].phonestringPhone number
results[].websitestringWebsite URL
results[].hoursobjectOperating hours (raw, is24_7, timezone)
results[].brandstringBrand name
results[].brandWikidatastringWikidata ID for the brand
results[].contactobjectContact info (phone, email, website)
results[].attributesobjectAdditional place attributes
results[].statusstringPlace status (e.g., active)
results[].sourceIdstringSource data identifier
results[].confidencenumberData confidence score (0-1)
results[].updatedAtstringLast updated timestamp (ISO 8601)
results[].scoresobjectIndividual scoring components
results[].scores.textnumberText relevance score
results[].scores.geonumberGeographic proximity score
totalintegerTotal matching results
executionTimeintegerQuery execution time (milliseconds)
queryStats.pruningEfficiencynumberCell pruning efficiency ratio
queryStats.cellsSearchedintegerNumber of H3 cells searched

2. Get Place by ID

Retrieve detailed information about a specific place.

GET/v1/places/{placeId}

Parameters

ParameterTypeRequiredDescription
placeIdstringYesPlace ID (format: {h3_r5}_{type}{osm_id})

Example Request

curl -H "Authorization: Bearer your-api-key" \
  "https://api.geog.dev/v1/places/8529a1003ffffff_n456789012"

Example Response

{
  "id": "8529a1003ffffff_n456789012",
  "score": 1.0,
  "name": "Blue Bottle Coffee",
  "description": "Specialty coffee roaster and retailer",
  "category": "cafe",
  "categories": ["cafe", "coffee_shop"],
  "location": {
    "lat": 37.7849,
    "lon": -122.4088
  },
  "address": "66 Mint St, San Francisco, CA 94103",
  "city": "San Francisco",
  "region": "California",
  "postcode": "94103",
  "phone": "+14158438220",
  "website": "https://bluebottlecoffee.com",
  "brand": "Blue Bottle Coffee",
  "sourceId": "way/123456789",
  "confidence": 0.98,
  "updatedAt": "2025-11-20T08:00:00Z"
}

Error Handling

Error Response Format

{
  "error": "error_type",
  "message": "Human-readable description",
  "code": "MACHINE_READABLE_CODE"
}

Error Codes

CodeStatusDescription
GEO_CONSTRAINT_REQUIRED400Missing required location field
INVALID_LOCATION400Invalid latitude or longitude values
INVALID_RADIUS400Radius must be a positive number
RADIUS_EXCEEDED400Radius exceeds 100,000m maximum
INVALID_JSON400Request body is not valid JSON
VALIDATION_ERROR400Request parameters failed validation
INVALID_ID400Place ID format is invalid
NOT_FOUND404Place not found
SERVICE_UNAVAILABLE503Search service is not configured
INDEX_NOT_AVAILABLE503Search index is not available

Best Practices

Search Optimization

  1. Always provide a location. The location field is required for all searches. The Places API uses H3 cell partitioning for efficient spatial queries.

  2. Use appropriate radius. Smaller radii return faster results. Start with the default 5,000m and increase only if needed.

  3. Combine text and category filters. Use query for free-text search and categories for structured filtering together for best results.

  4. Paginate large result sets. Use limit and offset for pagination instead of requesting all results at once.

Scoring Weights

Adjust the weights parameter to tune result ranking:

{
  "weights": { "text": 0.7, "geo": 0.3 }
}
  • Higher text weight prioritizes name/description matches
  • Higher geo weight prioritizes proximity to the search center
  • When omitted, the API uses balanced default weights

Caching

  • Place details (GET /v1/places/{id}) are stable and suitable for client-side caching
  • Search results may change as the index updates; cache with shorter TTLs