Places

curl "https://api.unmap.dev/places/nearby?category=bakery&near=-114.07,51.04&key=$UNMAP_KEY"
GET /places/searchfind places by name
GET /places/nearbyplaces of a category near a point
GET /places/{id}one place, by an id you already hold

/geocode/nearby is unchanged and keeps working. Places is a first-class presentation of the POI rows the geocoding corpus already carries, not a second store.

What /places/search adds over /geocode/search

It returns places. /geocode/search finds whatever best matches your query, which for "Calgary" is the city itself; that is the right answer for a geocoder and the wrong one when you wanted somewhere to go.

/places/{id} is new

The geocoder had no by-id lookup at all. If you stored a result, you had no way to refresh it. Now you do:

curl "https://api.unmap.dev/places/um:place:1234?key=$UNMAP_KEY"

A malformed id is a 404, not a 400. From your side "this place does not exist" and "this is not a well-formed id" are the same answer, and distinguishing them would leak our storage type into the contract. The id is opaque: a corpus rebuild may renumber it, so do not parse the tail.

From the SDK

import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({ key: process.env.UNMAP_KEY! });
 
const { data, meta } = await unmap.places.nearby("boulangerie", { near: [-73.57, 45.5] });
await unmap.places.search("calgary tower");
await unmap.places.get("um:place:1234");

meta comes back rather than being unwrapped away: without attribution you cannot comply with the licence the data came under. Places is exported from @unmap/geocoding too, if you want it without the rest of the SDK.

The fields we do not have

The response carries an id, names in every language the corpus holds, a category, coordinates and an address. It does not carry phone, website, opening_hours, accessibility, operator or a structured attributes bag.

Those fields are absent from the response, not present and null. The difference is deliberate:

  • "phone": null is a claim about the place, and usually a false one.
  • An absent key is a claim about our coverage, and it is true.

The loaders do not extract them today. Filling them needs loader work and a full corpus rebuild. Coverage says the same thing.

Response

{
  "data": [
    {
      "id": "um:place:1234",
      "source_id": "1234",
      "name": "RBC Royal Bank",
      "names": { "en": "RBC Royal Bank", "fr": "Banque Royale" },
      "category": "finance.bank",
      "category_group": "finance",
      "coordinates": [-114.0676, 51.0447],
      "address": { "housenumber": "339", "street": "8 Avenue SW", "city": "Calgary", "region": "AB" },
      "distance": 313,
      "source": "places.osm-poi"
    }
  ],
  "meta": { "attribution": "(c) OpenStreetMap contributors", "status": "current" }
}

distance appears on /places/nearby only. Absent address parts are omitted for the same reason the absent top-level fields are.

Categories

The same 89-category taxonomy /geocode/nearby uses, with English and French aliases resolved at the gateway, so ?category=boulangerie works from raw curl. See Geocoding for the full table.

EV charging

Charging stations are a Places category, not a separate API:

curl "https://api.unmap.dev/places/nearby?category=ev+charger&near=-114.07,51.05&key=$UNMAP_KEY"

transport.charging_station is the canonical id; ev charger and charging station are aliases.

Coverage is thin outside cities, and we measured it rather than guessing. On 2026-09-17, within 25 km of a downtown anchor: major cities hit the 50-result cap; Halifax returned 27; along the Trans-Canada, Banff 16, Swift Current 3, Kenora 2; Whitehorse 2; Yellowknife and Iqaluit zero.

Yellowknife returning nothing is more likely a missing record than a missing charger, and is the first thing we will check against an authoritative inventory. Iqaluit's zero may well be correct: it is off the road network entirely.

No network, connector type, power rating, port count, access or status. Same reason as the fields above: the corpus has no columns for them, so they are absent rather than null.

There is no authoritative Canadian station inventory behind this. NRCan's locator is not published as a dataset on open.canada.ca, and the federal funded-project datasets are lists of projects that received money rather than chargers that exist, so they are deliberately not used as a stand-in.

Known gaps

  • No deduplication across sources. The corpus conflates localities, not businesses. A chain with an entry in two sources can appear twice, and a persistent place identity that survives that is not built.
  • Coverage is OpenStreetMap's. Dense in cities, thin in rural Canada, and it varies street by street rather than by a published rule.
  • /places/{id} needs a current geocoding container. Against an older one it answers 404 and the body says the route may predate the deployment, rather than claiming the place is not there.

Found something wrong? Report it: POST /places/{id}/feedback takes a report about one place.