Places
curl "https://api.unmap.dev/places/nearby?category=bakery&near=-114.07,51.04&key=$UNMAP_KEY"GET /places/search | find places by name |
GET /places/nearby | places 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": nullis 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.