Places API
Errors and Quota Headers
On this page
Error format
Use stable codes for client behavior.
Search errors use stable machine-readable codes so callers can distinguish validation, auth, quota, coverage, and layer
selection failures without parsing prose messages. Every error body carries code,
message, request_id, and docs_url, a link to that code's entry on this page
(https://openplacesapi.com/docs/errors#<code>). Validation errors add
details, a list of field and message pairs for each rejected parameter.
{
"error": {
"code": "validation_error",
"message": "Invalid search request.",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"details": [
{ "field": "radius_mi", "message": "radius_mi must be greater than 0 and at most 50." }
],
"docs_url": "https://openplacesapi.com/docs/errors#validation_error"
}
} quota_exhausted also returns quota_limit and upgrade_url. Buy more searches from the dashboard billing page. There is no reset date or automatic charge.
{
"error": {
"code": "quota_exhausted",
"message": "No searches left on this account. Buy more at https://app.openplacesapi.com/#billing.",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"quota_limit": 2500,
"upgrade_url": "https://app.openplacesapi.com/#billing",
"docs_url": "https://openplacesapi.com/docs/errors#quota_exhausted"
}
} Statuses
HTTP status maps to the failure class.
| Status | Meaning |
|---|---|
400 | Invalid query parameter shape. |
401 | Missing bearer API key (unauthenticated) or invalid key (invalid_api_key). |
402 | Credit balance exhausted (quota_exhausted). |
403 |
Requested layer selection is well-formed but unavailable to the authenticated account.
layer_entry_cap_exceeded means the account is at its layer capacity: 250 entries before buying, 5,000 after any purchase. Archive entries, buy a pack, or email support@openplacesapi.com for more.
|
405 | Only GET is supported. |
422 | Reserved for unsupported_query; not currently returned. |
429 | rate_limited: the burst limit (120 requests per minute per account and per key, for everyone)
or the concurrency cap (8 searches in flight per account) was exceeded, or too many failed authentication
attempts came from one IP.
|
500 | Generic internal error. |
503 |
Temporarily unavailable: coverage_not_ready, search_timeout, or
quota_gate_unavailable. Retry after Retry-After seconds.
|
Error codes
Every public code and what to do about it.
Search errors link to their row through docs_url. Branch on code, not on
message; messages can change wording.
Management and billing responses from app.openplacesapi.com use a different shape:
{"error":{"code":"…","message":"…"}}, without the search API's request_id or docs_url fields.
The two management and billing codes below are marked in their descriptions.
| Code | Status | Meaning and client action |
|---|---|---|
validation_error | 400 | A parameter is missing, malformed, out of range, or unknown. Read details for each rejected field, fix the request, and do not retry it unchanged. |
unauthenticated | 401 | No bearer API key was sent. Send Authorization: Bearer opa_live_... from a server-side environment. |
invalid_api_key | 401 | The key is malformed, revoked, or unknown. Check the stored secret or create a new key in the dashboard; retrying with the same key will not help. |
method_not_allowed | 405 | Only GET is supported on /v1/places and /v1/categories. |
unsupported_query | 422 | Reserved for recognized but unsupported search shapes. Not currently returned; unsupported inputs are rejected with validation_error. |
layer_not_available | 403 | The layer selection is well-formed but not available to this account, or the preset does not exist. Check layers, layer_preset, or the key's default preset. |
quota_exhausted | 402 | The prepaid search balance is zero or expired and the request was not billed. Stop retrying. Buy more searches at upgrade_url; there is no reset or automatic charge. |
rate_limited | 429 | Too many requests per minute, more than 8 searches in flight for the account, or too many failed authentication attempts from one IP. Not billed. Wait Retry-After seconds and reduce request rate or parallelism. |
coverage_not_ready | 503 | The data for this location is not ready to search yet. Retry after Retry-After seconds (30). |
search_timeout | 503 | The search did not finish in time and was not billed. Retry after Retry-After seconds (5); a smaller radius or more specific query can help. |
quota_gate_unavailable | 503 | The API key or quota could not be checked, or the search reservation expired. Retry after Retry-After seconds. |
layer_entry_cap_exceeded | 403 | Management API: the account is at its layer-entry capacity (250 before a purchase, 5,000 afterward). Draft and published entries count; archive entries or email support for more capacity. |
internal_error | 500 | Unexpected server error. Retry with backoff, and include request_id if you contact support. |
Retries
Retry only what the API says is temporary.
When a response includes Retry-After, wait at least that many seconds before retrying. For
rate_limited it is the time until the burst window resets, or 1 when the account hit the
concurrency cap. For 503 codes it is a short backoff hint. quota_exhausted has no Retry-After or reset date. Stop and buy more at upgrade_url.
Each account can have at most 8 searches in flight at once. Requests over the cap are rejected immediately with
rate_limited and are not billed. Bound client-side parallelism to stay under the cap.
Search warnings
Empty results explain themselves.
Successful searches can include meta.warnings, a list of code and message
objects. Warnings do not change the HTTP status. unknown_category and
no_results_within_radius are only added to an empty first page (offset=0 with no results).
| Warning | Meaning 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.
|
unknown_category |
The category value is not a known Overture category. suggestions lists the closest
known slugs when any are found. Retry with one of them, or look slugs up with
GET /v1/categories.
|
no_results_within_radius |
Nothing matched within radius_mi. When a match was found within 100 miles,
nearest_match identifies the closest place found (public id, name, distance_mi, and locality and country when available). It stays outside results. nearest_match_distance_mi gives the same approximate distance and the message names the
radius_mi to retry with, or says the match is beyond the 50 mile maximum so the search should
start from a closer point. Without that field, nothing was found within 100 miles.
|
address_matching_skipped | A short mode=all query searched names only. Use a longer query to include addresses. |
query_relaxed | q had no exact matches, so the search was retried once with a relaxed form of q
(legal suffixes such as LLC, parenthesized asides, and connector words removed). The message
names the text used. Check that the results are the place you meant before relying on them.
|
category_inferred |
No place names matched q, even relaxed, so it was read as the closest category by meaning
(for example travel agency as travel_agent). The results are nearby places in
that category, named in the message and in meta.interpreted_as; none of them is a place
called q. Use mode=name to turn this off.
|
pagination_limit_reached |
More places match a category browse than its 1,000-place window can page through, so
next_offset is null even though the results continue. Narrow
radius_mi, raise min_confidence, or add q to reach the rest.
|
layer_entries_truncated | The per-search layer read limit was reached, so some published layer entries were not applied. |
{
"warnings": [
{
"code": "unknown_category",
"message": "\"coffeeshop\" is not a known category. Closest known categories: coffee_shop. List categories with GET /v1/categories?q=<text>.",
"suggestions": ["coffee_shop"]
}
]
} Headers
Quota and retry metadata travel in headers.
X-Quota-Limit and X-Quota-Remaining are sent on successful searches
and quota_exhausted responses. Other failures, including invalid keys and validation errors, do not carry quota headers.
| Header | Use |
|---|---|
X-Request-ID | Server-generated request identifier for support and debugging. |
X-Quota-Limit | Current credit balance allocation. |
X-Quota-Remaining | Unused, unexpired searches in the current balance. |
Retry-After |
Seconds to wait before retrying after rate_limited or a 503. A credit balance never resets.
|