Map Data & Risk
Map Data & Risk
Everything that layers on top of the base map: the map configuration manifest, category marker styles, icon sprites, vector/GeoJSON overlays, weather, and route-risk scoring that fuses traffic, weather, incidents, logistics zones, and enforcement assets.
Scope required: tiles for configuration, overlays, and weather; routing for the route-risk/enforcement POST endpoints.
[lng, lat]; bbox is west,south,east,north. Heavy overlays support a bbox/zoom/limit filter and a tile-cover planner for bounded loading. Most endpoints degrade gracefully (empty FeatureCollection with hasData:false) rather than erroring on bad input.GET /map/config
The full first-party map configuration manifest: base styles, overlays, categories, icons, weather, 3D, logistics zones, and a capabilities block describing public endpoints and performance limits. Fetch this once at startup to discover what's available and how to load it.
Top-level keys: layers, baseStyles, overlays, categories, icons, iconSpriteUrl, iconSpriteManifestUrl, categoryStyleManifest, threeD, logisticsZones, capabilities.
{
"baseStyles": [ { "key": "standard", "name": "Navvo", "kind": "base", "endpoint": "/api/v1/tiles/style?style=standard" } ],
"overlays": [ { "key": "traffic", "kind": "overlay", "layerType": "traffic", "tileUrl": "/api/v1/traffic/lines/tiles/{z}/{x}/{y}" } ],
"iconSpriteUrl": "/api/v1/map/icons/sprite.svg",
"capabilities": {
"publicEndpoints": { "config": "/api/v1/map/config", "routeRisk": "/api/v1/map/route-risk" },
"performance": { "defaultTileCoverCap": 64, "maxTileCoverCap": 256, "tileAddressedOverlays": true },
"vectorOverlays": { "enabled": true, "format": "mvt" }
}
}
GET /map/layers
A flat catalog of all configured layers: { items, baseStyles, overlays, total, requiredOverlays }. requiredOverlays lists the overlay layer types Navvo expects (e.g. traffic, transit, incidents, weather, logistics_zones).
GET /map/category-styles
Renderer-ready styling for place categories — marker colors, pin styles, icons, multilingual names, and aliases. Use it to draw category-colored markers that match Navvo's own map.
{
"version": 1,
"iconSpriteUrl": "/api/v1/map/icons/sprite.svg",
"categories": [
{
"slug": "restaurants",
"name": { "en": "Restaurants", "ar": "مطاعم" },
"color": "#F97316",
"pinStyle": "teardrop",
"zoomRange": { "min": 11, "max": 22 },
"icon": { "name": "utensils", "href": "/api/v1/map/icons/sprite.svg#navvo-icon-utensils" }
}
]
}
GET /map/icons/sprite.svg & sprite.json
sprite.svg returns an SVG symbol sprite (image/svg+xml) of all active icons (<symbol id="navvo-icon-…">). sprite.json returns the manifest describing each icon (name, id, href, size).
GET /map/readiness
A self-audit of the map surface — a list of boolean checks plus a summary (counts of base styles, overlays, categories, icons). Useful for diagnostics.
Overlays
Generic overlays serve stored map features as GeoJSON, vector tiles, or raster. Known layer types include traffic, transit, biking, terrain, incidents, speed_cameras, traffic_cameras, traffic_lights, weather, and logistics_zones.
GET /map/overlays/{layerType}
GeoJSON FeatureCollection for one overlay. Accepts bbox, limit, zoom.
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [35.91, 31.95] },
"properties": { "id": 12, "name": "Amman central speed camera", "layerType": "speed_cameras", "color": "#B91C1C" } }
],
"metadata": { "layerType": "speed_cameras", "name": "Speed cameras", "hasData": true }
}
biking (cycling network) and transit return live, viewport-driven network data (cached per area). For biking, each LineString/MultiLineString carries network (protected | shared | trail), surface, lit, oneway, and color. For transit, features carry kind (line | stop), mode (bus | metro | tram | rail), color, and (for lines) routeRef, lineName, network. Pass a bbox to scope the request.Tiled overlay access
| Endpoint | Returns |
|---|---|
GET /map/overlays/{layerType}/tile-cover | Tile URLs covering a bbox (bbox, zoom, maxTiles). |
GET /map/overlays/{layerType}/tiles/{z}/{x}/{y} | One tile as GeoJSON. |
GET /map/overlays/{layerType}/vector/{z}/{x}/{y} | One tile as a binary vector tile (application/x-protobuf, layer navvo). |
GET /map/logistics-zones.geojson
Logistics / SLA zone polygons as GeoJSON. Each feature carries zoneType, riskScore, costMultiplier, and routingPolicy — the same zones surfaced in /routing/plan results.
Weather
Weather overlays are stored polygons plus a live point lookup. type ∈ precipitation, temperature, clouds, storms, alerts; time ∈ -1h, now, +1h, +3h.
| Endpoint | Returns |
|---|---|
GET /map/weather/geojson | Weather polygons as GeoJSON (filters: type, time, bbox, limit, zoom). |
GET /map/weather/geojson/tiles/{z}/{x}/{y} | Weather GeoJSON for one tile. |
GET /map/weather/vector/{z}/{x}/{y} | Weather as a binary MVT (layer navvo_weather). |
GET /map/weather/tiles/{z}/{x}/{y} | A rendered SVG raster weather tile (image/svg+xml). |
GET /map/weather/tile-cover | Tile URLs covering a bbox. |
GET /map/weather-risk | Aggregate weather-risk preview (score, severity, warnings). |
GET /map/weather/point
Current point weather (from Navvo's weather service).
lon also accepted).metric (default) or imperial.{
"ok": true, "lat": 31.95, "lon": 35.91, "city": "Amman",
"temperature": 28, "unit": "C", "feelsLike": 30, "humidity": 35,
"windSpeed": 12, "windUnit": "km/h", "visibility": 16, "visibilityUnit": "km",
"condition": "Clear sky",
"aqi": 40, "aqiCategory": "Good", "pm25": 9, "pm10": 16, "dust": 1,
"source": "Navvo weather point service"
}
The response also carries live air quality: aqi (US AQI), aqiCategory (Good…Hazardous), pm25/pm10 (µg/m³), and dust (µg/m³, desert dust concentration). These are null if the air-quality source is briefly unavailable. This endpoint returns 400 on invalid coordinates (the only one in this module that does); upstream failures return 200 with ok:false.
GET /map/weather/forecast
Hourly weather forecast for a point — the next N hours (default 24, max 72).
lon also accepted).metric (default) or imperial.{
"ok": true, "lat": 31.95, "lon": 35.91, "city": "Amman",
"units": "metric", "unit": "C", "windUnit": "km/h", "hours": 6,
"forecast": [
{ "time": "2026-06-27T19:00:00.000Z", "temperature": 22.8, "condition": "Clear", "precipitationMm": 0, "windSpeed": 9, "humidity": 38 },
{ "time": "2026-06-27T20:00:00.000Z", "temperature": 22, "condition": "Clear", "precipitationMm": 0, "windSpeed": 8, "humidity": 41 }
]
}
| Field | Type | Notes |
|---|---|---|
forecast[].time | string | ISO hour |
forecast[].temperature | number | in unit (C/F) |
forecast[].condition | string | human label |
forecast[].precipitationMm | number | null | rain in the hour |
forecast[].windSpeed | number | in windUnit |
400 on invalid coordinates; upstream failures return 200 with ok:false and an empty forecast.
GET /map/weather/alerts
Derived weather warnings for a point — scans the next N hours of forecast and returns alerts for threshold breaches: heat (≥37 °C, especially relevant for MENA), cold/freezing (≤1 °C), heavy rain (≥4 mm/h), and strong wind (≥40 km/h). Each alert carries a severity (moderate/high/severe), a peak value, and the hour it occurs.
?lat=&lng=&hours= (default 24, max 72).
{
"ok": true, "provider": "navvo-weather", "lat": 24.63, "lon": 46.72, "city": "…",
"checkedHours": 48, "count": 1,
"alerts": [
{ "type": "heat", "severity": "severe", "message": "High temperatures up to 43°C", "valueC": 43, "at": "2026-06-28T12:00:00.000Z" }
]
}
count: 0 (empty alerts) means no thresholds were breached in the window. 400 on invalid coordinates.
GET /map/weather/cities
Weather pins for the cities/towns inside a viewport — used to label current conditions on the map at city zoom. Returns a GeoJSON FeatureCollection of points; only meaningful at zoom ≥ 7 (lower zooms return an empty collection quickly), and the count is capped so the map stays readable.
west,south,east,north.< 7 returns empty).metric (default) or imperial.{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [35.93, 31.95] },
"properties": { "name": "Amman", "temperature": 30, "unit": "C", "condition": "Clear",
"code": 0, "icon": "clear", "color": "#386BFF" } }
],
"metadata": { "layerType": "weather_cities", "name": "Weather", "hasData": true }
}
icon is a neutral family — one of clear, cloud, rain, storm, snow, fog — and code is its numeric equivalent (0–5).
GET /map/airquality/cities
Air-quality pins (US AQI + dust) for the cities/towns inside a viewport — the AQI counterpart of /map/weather/cities, for labelling air quality on the map at city zoom. Returns a GeoJSON FeatureCollection of points; only meaningful at zoom ≥ 7, and the count is capped (hard cap 20). Values are cached ~15 min per cell.
west,south,east,north.< 7 returns empty).{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [35.92, 31.95] },
"properties": { "name": "Amman", "aqi": 40, "aqiCategory": "Good",
"pm25": 10, "pm10": 16, "dust": 1 } }
],
"metadata": { "layerType": "air_quality_cities", "name": "Air quality", "hasData": true }
}
aqi is the US AQI; aqiCategory is its band (Good, Moderate, Unhealthy (sensitive), Unhealthy, Very unhealthy, Hazardous). pm25/pm10/dust are µg/m³. The same per-point values back the aqi/dust fields on /map/weather/point.
Route risk & enforcement
Score a route against live conditions across five layers — traffic, weather, incidents, logistics zones, and enforcement assets (cameras/signals) — using geometry intersection.
POST /map/route-risk
Scope: routing.
Request body
LineString/Feature/FeatureCollection, a raw array of [lng, lat] pairs, or any object with a coordinates field. (route is accepted as an alias.)preview.-1h, now (default), +1h, or +3h — which weather snapshot to score against.{
"routeId": "trip-42",
"timeOffset": "+1h",
"geometry": { "type": "LineString", "coordinates": [[35.91,31.95],[35.93,31.97],[35.95,31.99]] }
}
Response (200)
{
"ok": true,
"routeId": "trip-42",
"hasRouteGeometry": true,
"timeOffset": "+1h",
"scores": { "overall": 24, "traffic": 40, "weather": 10, "incidents": 0, "logistics": 32, "cameras": 16 },
"severity": "low",
"stack": [
{ "key": "traffic", "label": "Traffic speed", "score": 40, "severity": "medium", "detail": "Moderate congestion exposure on this route.", "count": 3 }
],
"warnings": [
{ "type": "traffic", "severity": "high", "title": "Heavy traffic segment", "detail": "18 km/h average · 42 samples", "location": { "lng": 35.93, "lat": 31.97 } },
{ "type": "logistics", "severity": "medium", "title": "Amman core congestion SLA", "location": { "lng": 35.91, "lat": 31.97 } }
]
}
| Field | Description |
|---|---|
scores | 0–100 per layer plus a weighted overall. |
severity | low / medium / high from the overall score. |
stack[] | Per-layer breakdown (score, severity, detail, count, source). |
warnings[] | Specific hazards along the route, each with a location anchor { lng, lat }. |
GET /map/route-risk (scope tiles) that takes the route via a coords query string of lng,lat pairs separated by ; — handy for quick previews without a request body.POST /map/route-enforcement
Scope: routing. Returns just the enforcement checkpoints (speed cameras, traffic cameras, traffic lights) along the route. Same request body as route-risk.
{
"ok": true,
"routeId": "trip-42",
"count": 2,
"items": [
{ "id": "speed_camera-0", "type": "speed_camera", "title": "Amman central speed camera", "detail": "Speed camera on or near route · 60 km/h", "confidence": 0.84, "location": { "lng": 35.92, "lat": 31.96 } }
]
}