Open Places API
Guides Layer Selection

Places API

Layer Selection

How to select Overture, the Open Places API community layer, and account-owned layers in Places API requests.
On this page

How layers work

Layer order is precedence order.

The default stack uses the Overture-backed base layer and the Open Places API community layer. Authenticated callers can also select account-owned layers or a saved preset. Higher layers win when they explicitly target a lower-layer place.

Rule The stack starts with base, then optional open, then account layers — so layers=base,open,account:field-team reads bottom-up.

Explicit selection

Use layers for a specific ordered stack.

Use layers when a request needs deterministic layer membership. Account layers use the account:<layer_slug> token and come last.

Request URL layers
GET /v1/places?q=coffee&lat=40.7128&lon=-74.0060&layers=base,open,account:field-team

Presets

Save presets and set key defaults.

Presets are useful for production defaults, customer-specific views, or partner-managed entries. A request can use layers or layer_preset, but not both.

  1. Create a preset on the dashboard's Layers page, or with POST /v1/layer-presets, choosing the layer stack.
  2. Make it a search key's default in Layers → Presets and key defaults → Key defaults, or send PATCH /v1/api-keys/:id/default-layer-preset with layerPresetId set to the preset's ID.
  3. Search with that key and omit layers and layer_preset to use its default.

An explicit layers or layer_preset in the request overrides the key default. If the default preset is archived, searches using it fail with layer_not_available instead of falling back.

Search keys also authenticate MCP. The MCP search_places tool has no layers or layer_preset input, so an agent uses its key's default preset. See Connect an agent (MCP).

Request URL preset
GET /v1/places?q=coffee&lat=40.7128&lon=-74.0060&layer_preset=production

Sharing

Share a layer with another account.

Sharing gives another Open Places account read-only access to a layer: one team maintains the entries, and other accounts search them. The receiving account cannot change the layer. Only published entries affect searches.

Open the Sharing panel on the dashboard's Layers page, or send POST /v1/layers/:id/grants to https://app.openplacesapi.com with a Control Plane Token that has grants:write. You need the other account's ID, shown on their Layers page, and a name for them to use. Send those as granteeAccountId and aliasSlug:

JSON bodygrant access
{
  "granteeAccountId": "00000000-0000-4000-8000-000000000021",
  "aliasSlug": "partner-places"
}

Replace the example account ID with the recipient's ID. The name must start with a lowercase letter or number, use only lowercase letters, numbers, hyphens or underscores, and be at most 63 characters. It cannot collide with one of the recipient's own layer slugs or another grant's name, including archived layers and revoked grants. Only one active grant is allowed per layer and receiving account.

The receiver adds account:<name> to layers using their own search API key. For the example name above:

cURLreceiver's search
curl -G "https://api.openplacesapi.com/v1/places" \
  --data-urlencode "q=coffee" \
  --data-urlencode "lat=40.7128" \
  --data-urlencode "lon=-74.0060" \
  --data-urlencode "layers=base,open,account:partner-places" \
  -H "Authorization: Bearer $OPA_KEY"

They can also use the name in a preset's selection.accountLayerSlugs through the management API (for example, ["partner-places"], without the account: prefix). Shared layers do not yet appear in the receiver's dashboard list or its preset picker.

Revoke access in the Sharing panel or with POST /v1/layer-grants/:id/revoke using grants:write. Revoking stops access on the next search request, including searches that use a preset containing the shared layer.

Operations

Account layers can express product-specific changes.

Operation Effect in search
Create place Adds an account-only place with an account-scoped public ID.
Update place field Patches selected fields on a targeted lower-layer place while preserving the public ID.
Suppress place Removes a targeted lower-layer place from the effective result set.
Mark closed, moved, or duplicate Represents product-specific status without mutating the shared base layer.
cURL layer stack
curl -G "https://api.openplacesapi.com/v1/places" \
  --data-urlencode "q=coffee" \
  --data-urlencode "lat=40.7128" \
  --data-urlencode "lon=-74.0060" \
  --data-urlencode "layers=base,open,account:client-a" \
  -H "Authorization: Bearer $OPA_KEY"

Imports

Import entries in bulk.

Import between 1 and 500 entries at a time. The dashboard's Import JSON form takes an array of entry objects like this one. This example adds Bryant Park to your layer and hides a coffee result from your searches; replace the target ID with the place_id you want to suppress.

JSON arraytwo entries
[
  {
    "clientEntryKey": "bryant-park",
    "operation": "create_place",
    "fieldsPatch": { "name": "Bryant Park" },
    "country": "US",
    "latitude": 40.7536,
    "longitude": -73.9832
  },
  {
    "clientEntryKey": "hide-coffee-result",
    "operation": "suppress_place",
    "targetPublicPlaceId": "overture:a27acb33-8aaf-4cf8-a979-4dc1cfe5dc82",
    "fieldsPatch": {},
    "country": "US"
  }
]

Every entry needs operation and fieldsPatch; use an empty object for a suppression. A create_place entry cannot have a targetPublicPlaceId. Other operations require that field with an overture:, open: or acct: public ID. For a new place, include a name and coordinates so it can be found in searches.

To automate imports, send POST /v1/layers/:id/imports to https://app.openplacesapi.com with a Control Plane Token that has imports:write. Wrap the array in an object with entries and optional publish. Save that object as import.json, then run:

cURLimport entries
curl "https://app.openplacesapi.com/v1/layers/$LAYER_ID/imports" \
  -H "Authorization: Bearer $OPA_CONTROL_TOKEN" \
  -H "Content-Type: application/json" \
  --data @import.json

Set publish: true to publish every imported entry immediately. If publish is false or omitted, all imported entries become drafts. This flag overrides each entry's state, including when updating entries on re-import. The dashboard's “Publish imported entries immediately” checkbox controls the same flag.

An optional clientEntryKey (1–160 characters) identifies an entry within this layer. Re-importing the same key replaces that entry's supplied data instead of adding another entry; an archived entry is restored. Keep keys unique within each import. Without a key, every import creates a new entry. Imports also count toward your plan's layer-entry allowance and the published-entry runtime limits.

Runtime limits

Layer reads are live today and capped per country set.

Public searches live-read published account-layer entries from the control plane. For each layer-enabled search, the runtime loads up to 5,000 published account-layer entries matching the selected account-layer stack and request country set. Entries without a country count only when they target a current candidate place or their coordinates fall within the request's bounding box. If no country set is available, the runtime uses those target and coordinate checks for all entries.

Limit Keep active published entries below 5,000 for any one country in a selected layer stack. Approved Open Places community enhancements are loaded separately and currently capped at 1,000 entries for the request country set.

The dashboard warns when a layer approaches the 5,000-entry runtime cap. Archive stale entries, split very large imports across layers or presets, or keep high-volume compiled layer artifacts on your roadmap for workloads that need more than the live-read path.

Management API

Use Control Plane Tokens for layer writes.

Public search API keys authenticate /v1/places and MCP searches. External systems that create layers, write entries, run imports, save presets, manage grants, or update API-key layer defaults should use scoped Control Plane Tokens from the dashboard.

Scopes layers:read, layers:write, entries:write, imports:write, presets:write, grants:write, and api_keys:write_defaults.
Endpoint Scope
GET /v1/layers layers:read
POST /v1/layers, PATCH /v1/layers/:id, POST /v1/layers/:id/archive layers:write
POST /v1/layers/:id/entries, PATCH /v1/layers/:id/entries/:entryId entries:write
POST /v1/layers/:id/imports imports:write
POST /v1/layer-presets, PATCH /v1/layer-presets/:id presets:write
POST /v1/layers/:id/grants, POST /v1/layer-grants/:id/revoke grants:write
PATCH /v1/api-keys/:id/default-layer-preset api_keys:write_defaults
cURL list layers
curl https://app.openplacesapi.com/v1/layers \
  -H "Authorization: Bearer $OPA_CONTROL_TOKEN"
cURL create layer
curl https://app.openplacesapi.com/v1/layers \
  -H "Authorization: Bearer $OPA_CONTROL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Field team","slug":"field-team"}'