Road events
Three endpoints over one set of data:
GET /incidents | every current road event |
GET /closures | the subset where a road is actually shut |
GET /road-conditions | the subset carrying a surface condition |
British Columbia only. See Coverage for why, because the reason is not technical.
curl "https://api.unmap.dev/closures?key=$UNMAP_KEY&limit=3"{
"data": [
{
"id": "um:road:ca-bc:drivebc.ca%2FRIDE-101916",
"source_id": "drivebc.ca/RIDE-101916",
"jurisdiction": "CA-BC",
"type": "closure",
"severity": "major",
"condition": "closed",
"description": "Bridge construction at Kicking Horse Drive. Starting Fri Sep 25. All day, every day. Closed for repairs.",
"roads": [
{ "name": "Other Roads", "direction": "both", "closed": true, "from": "Kicking Horse Drive", "condition": "closed" }
],
"geometry": { "type": "Point", "coordinates": [-116.96, 51.29] },
"source_updated_at": "2026-09-17T08:06:31-07:00",
"unmap_updated_at": "2026-09-17T15:55:16.508Z",
"source": "roads.drivebc-open511"
}
],
"meta": {
"source": "Government of British Columbia, DriveBC: DriveBC Open511 events",
"status": "current",
"attribution": "Contains information licensed under the Open Government Licence - British Columbia"
}
}From the SDK
import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({ key: process.env.UNMAP_KEY! });
const { data, meta } = await unmap.roads.closures({ jurisdiction: "CA-BC" });
if (meta.unavailable?.length) {
// A province could not be reached. An empty `data` is NOT the same as "nothing is shut".
console.warn(meta.unavailable);
}unmap.roads.incidents(), .closures() and .conditions() take the same query as the endpoints.
Parameters
All three endpoints take the same ones.
| Parameter | Notes |
|---|---|
jurisdiction | Comma-separated ISO 3166-2. Only CA-BC today; anything else is a 400 naming what is covered |
bbox | west,south,east,north in WGS84 |
near + radius | lng,lat and metres, default 25000, max 500000 |
type | closure, incident, construction, weather, restriction, ferry, hazard, special_event, unknown |
severity | minor, major, unknown |
status | active, planned, archived |
updated_since | ISO 8601. Events the publisher changed at or after this time |
limit | 1 to 500, default 100 |
Results are sorted most severe first, then most recently updated.
Four decisions worth knowing about
A closure means the publisher said closed. It is read from the upstream's road state and from
nothing else. The event category says why a road is affected, never whether it is shut: on the
day this shipped, British Columbia's 16 closures were spread across construction and incident
events, and several construction events described brief closures in prose while reporting all lanes
open. Those do not appear in /closures.
The publisher's description is returned verbatim. Our categories are a lossy projection of someone else's taxonomy, and the sentence a driver actually needs ("Single Lane Alternating Traffic will only be required for a brief duration during mobilization") is in the prose. If our category and the description disagree, believe the description and tell us.
An unmapped upstream value becomes unknown, never a guess. A feed inventing SNOW_SQUALL
surfaces as unknown with its description intact rather than being rounded into weather because
the word looks weathery.
/road-conditions is thin, and dry is rare. Open511's road state describes lane availability,
not the surface. All lanes being open is not evidence of a dry road, so unmap reports unknown
rather than inventing a measurement nobody took.
Freshness, and what happens when a province is down
These are polled live behind a 60-second edge cache, not ingested on a schedule. A road event that is an hour old is worthless, and a cached snapshot hides its own age.
meta.status is computed from what was just fetched: current normally, stale when the upstream
is answering but nothing in it has moved in over an hour, which usually means a problem at their
end rather than an unusually quiet province.
When a jurisdiction cannot be reached, the response says so rather than returning an empty list:
{
"data": [],
"meta": {
"status": "partial",
"unavailable": [{ "jurisdiction": "CA-BC", "reason": "upstream timed out" }]
}
}That distinction matters most on /closures, where an empty list reads as "nothing is shut" to
someone deciding whether to drive. If every requested jurisdiction fails, the status code is 503.
Coverage
One province of thirteen, and the gap is worth stating plainly.
511 Alberta requires an API key. An unauthenticated request returns
<Error><Message>Invalid Key</Message></Error>, verified 2026-09-17. Alberta is absent because
nobody has registered for a key, not because the adapter is hard. Open511 is a specification rather
than one province's invention, so a second jurisdiction serving it openly is a configuration entry
rather than new code.
Other limits:
- Provincial highways only. Municipal streets are not in this feed.
- 500 events per response, unpaged. British Columbia carried 286 active events when this was first measured, so the cap is not currently binding. It will be for a larger jurisdiction.
- Routing does not avoid closures. Nothing in
/routeis affected yet. Feeding confirmed closures into the routing graph is a separate stage and is not done.