Open Places API
API Reference API Reference

Places API

API Reference

Reference for the Open Places API search and category endpoints, query parameters, responses, warnings, headers, and OpenAPI contract.
On this page

Operation

GET /v1/places

Searches place names and scoped addresses near a latitude/longitude point, or lists a category in an area when category is supplied. The source contract has a readable preview at OpenAPI YAML.

GET https://api.openplacesapi.com/v1/places

Authenticated public search endpoint for server-side integrations.

Query parameters

Inputs accepted by the search endpoint.

Name Type Required Details
q string Usually Search text, up to 128 characters after normalization, with at least 3 searchable letters or numbers (2 for a contiguous CJK query such as 咖啡). Required unless category is supplied. In the default mode=all, a q that names a kind of place also searches that category; see category words in q.
category string No Exact Overture category slug; look slugs up with GET /v1/categories. Matches primary and alternate categories plus hierarchy ancestors of the primary category, so a parent such as food_and_drink also matches its subcategories. Enables category browse and makes q optional. Reviewed legacy aliases resolve to the current slug in meta.category, with a category_alias warning and resolved_category. Legacy parent aliases such as travel → travel_service, automotive → automotive_service, and attractions_and_activities → arts_and_entertainment can match fewer categories than the old filter; check category_alias and choose a current slug for the scope you need. An unknown slug returns an unknown_category warning with suggestions.
lat number Yes Latitude from -90 to 90.
lon number Yes Longitude from -180 to 180.
radius_mi number No Must be greater than 0. Defaults to 25; maximum is 50.
mode enum No all, name, or address. Defaults to all, which matches names and addresses and reads category words in q. name matches place names literally, without category interpretation. address requires at least 4 searchable letters or numbers.
limit integer No Minimum 1. Defaults to 10; text search maximum is 20, category browse maximum is 50.
offset integer No Category-browse pagination offset. offset + limit can be at most 1000, so category browse reaches the first 1,000 places in sort order. Use meta.next_offset for the next page; it is null on the last page. Each page is one billed search.
min_confidence number No Minimum confidence from 0 to 1. Omit for no confidence filter.
sort enum No relevance (default) or distance. distance returns the same matches nearest first, and category pages from offset walk outward from lat/lon. Add min_confidence so low-confidence records don't fill the nearest results.
layer_preset string No Account-owned preset slug. Mutually exclusive with layers.
layers string No Explicit ordered selection such as base,open,account:client-a. At most 10 account layers.

Category words in q

A plain q=pharmacy searches the pharmacy category too.

In the default mode=all, when category is not supplied and q names a kind of place, the search also covers the matching categories. Top-level groups such as shopping or food_and_drink are never read from q.

A whole-q category phrase such as pharmacy, chemist, fire station, or pizza near me lists places in the category first (primary-category and subcategory matches before alternate-category matches; within each, confidence bands of at least 0.9, at least 0.6 but below 0.9, then below 0.6 (including missing confidence), nearest first within each band), then other places whose name matches q. Address-only matches are dropped. A category phrase plus other words, such as boots pharmacy, keeps full-text matches first, then adds places in the category whose names match the other words.

meta.interpreted_as reports the reading (type, categories, text, and a message), or is null when q was searched as plain text. Each result can carry match: name, address, category, or name_and_category. Use mode=name to match a literal name, and an explicit category with offset to page through a category, up to the first 1,000 places per query area.

If a search with q finds nothing, it is retried once with a relaxed q: trailing legal suffixes such as LLC or GmbH, parenthesized asides, and the words and, the, and of are dropped. Relaxed results must contain the remaining words as whole words of the place name and carry a query_relaxed warning. If that still finds nothing, q may be read as the closest category by meaning (for example tienda de computadoras as computer_store): the results are nearby places in that category, with match: category and a category_inferred warning.

Responses

Success, quota, and error responses are explicit.

Status Response
200 Search completed, including zero-result searches.
400 Validation error; error.details lists each rejected field.
401, 403 Authentication or layer authorization failure.
402, 429, 503 Quota exhausted, per-account rate limit exceeded, or temporarily unavailable.

Only requests with an explicit category can page. Follow meta.next_offset; each page is one billed search. It can be null because the next page would cross the 1,000-place window even when more places match; check pagination_limit_reached in meta.warnings.

Node.jscategory paging
const apiKey = process.env.OPA_KEY;
if (!apiKey) throw new Error("OPA_KEY is required");
let offset = 0;
do {
  const url = new URL("https://api.openplacesapi.com/v1/places");
  url.search = new URLSearchParams({
    category: "cafe", lat: "40.7128", lon: "-74.0060",
    limit: "50", offset: String(offset),
  }).toString();
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  if (!response.ok) throw new Error(`Search failed: ${response.status}`);
  const body = await response.json();
  console.log(body.results);
  offset = body.meta.next_offset;
} while (offset !== null);

The rate limit is 120 requests per minute per account for everyone, with at most 8 searches in flight per account at once. Purchases add searches and extend the whole balance for 12 months. X-Quota-Limit describes the current balance allocation; X-Quota-Remaining is the number left. There is no reset header. Every error body includes a docs_url linking to its entry on the errors page.

JSON SearchResponse
{
  "results": [
    {
      "place_id": "overture:08f2c...",
      "name": "Devocion",
      "lat": 40.688838,
      "lon": -73.979914,
      "distance_mi": 2.15,
      "category": "cafe",
      "categories": ["cafe", "coffee_shop"],
      "category_hierarchy": ["food_and_drink", "casual_eatery", "cafe"],
      "address": {
        "locality": "Brooklyn",
        "country_code": "US"
      },
      "phone": "+17185551212",
      "website": "https://www.devocion.com",
      "confidence": 0.92,
      "operating_status": "operational",
      "match": "category"
    }
  ],
  "meta": {
    "request_id": "00000000-0000-4000-8000-000000000000",
    "data_source": "overture",
    "data_release": "2026-10-21.0",
    "data_releases": ["2026-10-21.0"],
    "q": "coffee",
    "category": null,
    "min_confidence": 0.85,
    "sort": "relevance",
    "mode": "all",
    "lat": 40.7128,
    "lon": -74.006,
    "radius_mi": 25,
    "limit": 10,
    "offset": 0,
    "next_offset": null,
    "interpreted_as": {
      "type": "category",
      "categories": ["coffee_shop", "cafe"],
      "text": null,
      "message": "Read \"coffee\" as the category coffee_shop (also cafe): places in that category come first, then other name matches. Use mode=name to match names only, or category=coffee_shop with offset to page through every match."
    },
    "warnings": [],
    "layer_selection": {
      "source": "default",
      "preset": null,
      "layers": [{ "type": "overture_base" }, { "type": "open" }]
    }
  }
}

Warnings

Read meta.warnings before giving up.

Successful responses can carry warnings. On an empty first page, unknown_category lists the closest known categories in suggestions, and no_results_within_radius reports nearest_match_distance_mi and a nearest_match object (public id, name, distance_mi, and locality and country when available) when a match is found within 100 miles. That place stays outside results, with a message naming the radius_mi to retry with. query_relaxed means q had no exact matches and the results are for the relaxed text named in the message. category_inferred means nothing matched by name, so the results are nearby places in the closest category by meaning. pagination_limit_reached means more places match than a category browse can page through, so next_offset is null before the end of the results. See search warnings for every code.

WarningMeaning and client action
category_alias A reviewed legacy category was resolved to resolved_category, also returned in meta.category. This warning can appear on any successful page. Legacy parent aliases can narrow the old filter; check the resolved slug against the scope you need.

Categories

GET /v1/categories

Lists valid category values from the Overture category taxonomy, including parent groups. It is public, needs no API key, does not count against quota, and is cacheable for an hour. Without q it returns every category alphabetically; with q (1 to 64 characters) it returns the best matches, 20 by default. limit accepts 1 to 100. Unknown parameters return validation_error.

GET https://api.openplacesapi.com/v1/categories

Category lookup for building category requests.

JSON CategoryListResponse
curl "https://api.openplacesapi.com/v1/categories?q=coffee&limit=3"
{
  "categories": [
    {
      "category": "coffee_shop",
      "label": "Coffee shop",
      "parent": "non_alcoholic_beverage_venue",
      "hierarchy": [
        "food_and_drink",
        "non_alcoholic_beverage_venue",
        "coffee_shop"
      ]
    },
    {
      "category": "coffee_roastery",
      "label": "Coffee roastery",
      "parent": "coffee_shop",
      "hierarchy": [
        "food_and_drink",
        "non_alcoholic_beverage_venue",
        "coffee_shop",
        "coffee_roastery"
      ]
    },
    {
      "category": "coffee_and_tea_supplies",
      "label": "Coffee and tea supplies",
      "parent": "food_and_beverage_store",
      "hierarchy": [
        "shopping",
        "food_and_beverage_store",
        "coffee_and_tea_supplies"
      ]
    }
  ],
  "meta": {
    "request_id": "00000000-0000-4000-8000-000000000000",
    "q": "coffee",
    "count": 3,
    "total": 2201
  }
}