Navvo
API Reference

Traffic & Incidents

Live and typical congestion, traffic-aware ETAs, and crowdsourced road incidents.

Traffic & Incidents

Real-time and typical congestion derived entirely from Navvo's own anonymous probe network (there is no third-party traffic feed), plus crowdsourced road incidents.

Scope required: traffic (the traffic-aware POST /traffic/route needs both routing and traffic).

Coordinates are GeoJSON [lng, lat]. The bbox parameter is west,south,east,north. Congestion line "tiles" return GeoJSON, not binary vector tiles. Congestion vocabulary: levelfree | slow | heavy | standstill; congestionlight | moderate | heavy | blocked.

GET /traffic/layers

Layer descriptor and legend for the live traffic layer.

{
  "layerType": "traffic",
  "name": "Live traffic",
  "source": "navvo-user-traffic",
  "tilePattern": "/api/v1/traffic/lines/tiles/{z}/{x}/{y}",
  "refreshSeconds": 60,
  "legend": {
    "free": { "label": "Free flow", "color": "#2dbe60" },
    "slow": { "label": "Slow", "color": "#f9a825" },
    "heavy": { "label": "Heavy", "color": "#e84b36" },
    "standstill": { "label": "Standstill", "color": "#a01a12" }
  }
}

GET /traffic/summary

Aggregate live conditions over a bbox (or globally if bbox is omitted).

Query parameters

bbox
string
west,south,east,north. Omit to summarize all current edges.
{
  "source": "navvo-user-traffic",
  "bbox": "35.85,31.90,35.99,31.99",
  "conditions": {
    "hasData": true,
    "sampledSegments": 128,
    "congestionScore": 0.42,
    "level": "slow",
    "congestion": "moderate",
    "summary": "Slow moving",
    "breakdown": [
      { "level": "free", "segments": 60, "share": 46.9 },
      { "level": "slow", "segments": 40, "share": 31.2 }
    ]
  },
  "freshnessAt": "2026-06-09T08:55:00.000Z",
  "freshnessLabel": "From Navvo users"
}

congestionScore is a 0–1 weighted mean.

Typical-traffic blend (cold start)

When no live probes cover the view, the summary doesn't go blank: it answers from Navvo's learned typical profile for the current hour instead. The response is clearly flagged — it is never presented as live:

{
  "source": "navvo-typical-traffic",
  "bbox": "35.85,31.90,35.99,32.02",
  "conditions": {
    "hasData": true, "sampledSegments": 0, "typical": true,
    "level": "free", "congestion": "light",
    "summary": "Typically free flowing now", "congestionScore": 0.11,
    "breakdown": []
  },
  "freshnessAt": null,
  "freshnessLabel": "Typical for this hour (no live reports yet)"
}

Switch on source: navvo-user-traffic means live probe data (freshnessLabel: "From Navvo users"); navvo-typical-traffic means the historical estimate — show it with the freshnessLabel (e.g. as "Typical for this hour"), not as a live reading. When there is neither live nor typical coverage, hasData is false and level is null with freshnessLabel: "Awaiting Navvo user traffic".


GET /traffic/lines/tiles/{z}/{x}/{y}

Live congestion lines for one tile, as a GeoJSON FeatureCollection (only edges observed in the last ~6 hours).

curl -s "https://navvo.io/api/v1/traffic/lines/tiles/14/9783/6592" -H "x-api-key: nvvo_YOUR_KEY"
{
  "type": "FeatureCollection",
  "hasData": true,
  "features": [
    {
      "type": "Feature",
      "properties": { "level": "slow", "congestion": "moderate", "color": "#f9a825", "edgeId": "edge-12345", "averageSpeedKph": 22.4, "freeFlowSpeedKph": 50 },
      "geometry": { "type": "LineString", "coordinates": [[35.9106, 31.9539], [35.9121, 31.9558]] }
    }
  ]
}

GET /traffic/lines/tile-cover

Compute the tiles covering a bbox for the live line layer, with ready-made URLs.

Query parameters

bbox
string required
west,south,east,north.
zoom
number
Tile zoom, clamped to 12–16. Defaults to 14.
maxTiles
number
Cap on returned tiles, clamped to 1–48. Defaults to 24.
{
  "layerType": "traffic", "zoom": 14, "capped": false,
  "tilePattern": "/api/v1/traffic/lines/tiles/{z}/{x}/{y}",
  "tiles": [ { "z": 14, "x": 9783, "y": 6592, "url": "/api/v1/traffic/lines/tiles/14/9783/6592" } ]
}

GET /traffic/predicted/tiles/{z}/{x}/{y}

Typical/predicted congestion for one tile (sample-weighted historical averages), as GeoJSON. Identical shape to the live tile, but each feature's properties carries "predicted": true. A companion GET /traffic/predicted/tile-cover works like the live tile-cover and additionally accepts an at ISO timestamp (folded into the returned URLs).


POST /traffic/route

Compute a route and enrich its ETA with live, Navvo-sourced traffic. This is the traffic-aware sibling of POST /routing/route: it routes via the Navvo routing engine, samples congestion along the path, and returns a traffic-adjusted ETA plus the route split into colored segments.

Scopes required: routing and traffic.

Request body

locations
array required
Array of { "lon": number, "lat": number, "name"?: string }. At least 2 required.
costing
string
auto (default), truck, bicycle, pedestrian, or motor_scooter.
departureTime
string
ISO timestamp for departure; basis for arrivalTime. Defaults to now.
language
string
Narrative language. Defaults to en-US.
shape
array
Optional geometry of a route you are already displaying, as an array of [lon, lat] pairs. When provided, congestion is sampled along this exact shape and no route is re-planned — guaranteeing the colored segments match your drawn line (a re-planned route can diverge from a user-chosen alternative). Up to 10,000 points accepted (internally resampled to ≤ 2,000).
baseSeconds
number
Optional no-traffic duration (seconds) of the provided shape — used as the basis for durationInTrafficSeconds. Only meaningful together with shape; without it the traffic-adjusted ETA fields are 0 and only the colored segments are useful.
{
  "locations": [ { "lon": 35.91, "lat": 31.95 }, { "lon": 35.95, "lat": 31.99 } ],
  "costing": "auto",
  "departureTime": "2026-06-09T08:30:00.000Z"
}

With your own displayed geometry (recommended when you render the route yourself):

{
  "locations": [ { "lon": 35.91, "lat": 31.95 }, { "lon": 35.95, "lat": 31.99 } ],
  "shape": [ [35.91, 31.95], [35.917, 31.958], [35.93, 31.972], [35.95, 31.99] ],
  "baseSeconds": 540,
  "costing": "auto"
}

Response (201)

{
  "provider": "navvo-user-traffic-routing",
  "available": true,
  "distanceKm": 6.42,
  "baseDurationSeconds": 540,
  "durationInTrafficSeconds": 637,
  "delaySeconds": 97,
  "departureTime": "2026-06-09T08:30:00.000Z",
  "arrivalTime": "2026-06-09T08:40:37.000Z",
  "traffic": {
    "hasData": true,
    "congestionScore": 0.33,
    "level": "slow",
    "trafficFactor": 1.18,
    "congestedShare": 50
  },
  "segments": {
    "type": "FeatureCollection",
    "features": [
      { "type": "Feature", "properties": { "level": "free", "color": "#1A73E8" }, "geometry": { "type": "LineString", "coordinates": [[35.91, 31.95], [35.92, 31.96]] } },
      { "type": "Feature", "properties": { "level": "slow", "color": "#F9A825" }, "geometry": { "type": "LineString", "coordinates": [[35.92, 31.96], [35.95, 31.99]] } }
    ]
  },
  "legend": { "free": { "label": "Free", "color": "#1A73E8" }, "slow": { "label": "Slow", "color": "#F9A825" } }
}
FieldDescription
baseDurationSecondsETA from Navvo's routing engine, no traffic.
durationInTrafficSecondsTraffic-adjusted ETA (base × trafficFactor).
delaySecondsExtra time due to traffic.
traffic.trafficFactorMultiplier applied to the base duration.
segmentsThe route as a GeoJSON FeatureCollection, colored by congestion — render directly on a map.

If the routing engine is down, available is false, durations are 0, and segments is empty.


Incidents

Crowdsourced road incidents — jams, closures, accidents, hazards, and more. Scope required: traffic.

Incident typejam, closure, accident, hazard, weather, breakdown, speed_check, construction, lane_closure, visibility. severity is 15. Only active, non-expired incidents are returned.

GET /incidents/types

The catalog of supported incident types — for building a "report incident" type picker. Each entry carries a human label, a default severity, the default lifetime (defaultTtlMinutes), and whether the type blocks routing (route-blocking types are routed around; soft types only alert the driver).

curl -s "https://navvo.io/api/v1/incidents/types" -H "x-api-key: $NAVVO_API_KEY"
{
  "provider": "navvo-incidents", "count": 10, "confirmBumpMinutes": 25, "maxTtlMinutes": 720,
  "types": [
    { "type": "jam", "label": "Traffic jam", "defaultSeverity": 2, "defaultTtlMinutes": 90, "routeBlocking": false },
    { "type": "closure", "label": "Road closure", "defaultSeverity": 4, "defaultTtlMinutes": 240, "routeBlocking": true },
    { "type": "accident", "label": "Accident", "defaultSeverity": 4, "defaultTtlMinutes": 120, "routeBlocking": true }
  ]
}

The type values are exactly what POST /incidents and POST /incidents/report accept; confirmBumpMinutes/maxTtlMinutes describe how confirmations extend an incident's life.

GET /incidents

List active incidents, severity-then-recency ordered, with layer metadata.

Query parameters

bbox
string
west,south,east,north spatial filter.
type
string
Filter by incident type.
limit
number
Max items, 1–250 (also capped by zoom).
zoom
string
Controls the default limit cap.
{
  "total": 1,
  "items": [
    {
      "id": "b1f2c3d4-…",
      "type": "accident",
      "status": "active",
      "location": "POINT(35.9106 31.9539)",
      "title": "Two-car collision",
      "severity": 4,
      "expiresAt": "2026-06-09T10:40:00.000Z",
      "confirmations": 3,
      "rejections": 0
    }
  ],
  "metadata": { "layerType": "incidents", "source": "navvo-incidents", "dataUrl": "/api/v1/incidents/geojson", "hasData": true }
}

items[].location is a WKT string; for parsed coordinates use the GeoJSON endpoint below.

GET /incidents/geojson

Active incidents as a GeoJSON FeatureCollection (coordinates [lng, lat]). Accepts the same bbox/type/limit/zoom filters. A GET /incidents/geojson/tiles/{z}/{x}/{y} per-tile variant and a GET /incidents/geojson/tile-cover planner are also available.

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [35.9106, 31.9539] },
      "properties": { "id": "b1f2c3d4-…", "type": "accident", "title": "Two-car collision", "severity": 4, "confirmations": 3, "rejections": 0 }
    }
  ],
  "metadata": { "layerType": "incidents", "hasData": true }
}

POST /incidents

Report a new incident.

Request body

type
string required
One of the incident types listed above.
lat
number required
Latitude.
lng
number required
Longitude.
title
string
Short title.
description
string
Free text.
severity
number
15. Defaults to 2.
ttlMinutes
number
Lifetime in minutes, 51440. Defaults to 180.
{ "type": "hazard", "lat": 31.9539, "lng": 35.9106, "title": "Debris on road", "severity": 3, "ttlMinutes": 120 }

Returns 201 with the created incident (status: "active", expiresAt set from ttlMinutes).

POST /incidents/report

The community-report helper — like POST /incidents but with auto-deduplication. If an active incident of the same type already exists within ~80 m, this is treated as a confirmation (bumps that incident's confirmations and refreshes its expiry) instead of creating a duplicate pin — the right behaviour when many drivers report the same jam or accident. Otherwise a new incident is created.

Same body as POST /incidents, plus an optional dedupMeters (default 80, max 500).

curl -s -X POST "https://navvo.io/api/v1/incidents/report" \
  -H "x-api-key: $NAVVO_API_KEY" -H "content-type: application/json" \
  -d '{ "type": "jam", "lat": 31.97, "lng": 35.92, "severity": 3, "title": "Heavy traffic" }'
{ "provider": "navvo-incidents", "merged": true, "distanceM": 31, "confirmations": 2, "incident": { } }
FieldTypeNotes
mergedbooleantrue if folded into a nearby same-type incident (a confirmation); false if a new one was created
distanceMnumber(when merged) distance to the matched incident
confirmationsnumber(when merged) the incident's confirmation count after this report
incidentobjectthe resulting incident

Use this from a "Report" button so repeated reports of one event converge on a single, increasingly-confirmed pin rather than cluttering the map.

POST /incidents/{id}/votes

Confirm or reject an incident (crowd validation). Returns 201 with the updated incident. An incident with 5+ rejections (and rejections > 2× confirmations) is auto-marked rejected and drops out of listings.

Request body

vote
string required
confirm or reject.
userId
string
Optional voter id.
{ "vote": "confirm" }

Road edits & closures

Road edits are authored on the Navvo platform (operations dashboard) and are the authoritative, longer-lived counterpart to crowd incidents: road closures, access restrictions, custom (drawn) roads, and attribute adjustments. Active edits appear on the map, here in the API, and — for closures/restrictions — are routed around automatically (see roadEditConstraints in the route response). Each edit can be permanent or temporary (a start/end window).

Required scope: tiles

GET /road-edits/geojson

Active road edits in a viewport as a GeoJSON FeatureCollection with mixed geometry (LineString for road segments, Polygon for area closures, Point for point edits). Only edits effective now are returned (a scheduled edit appears once its start time passes; an expired or disabled one drops out).

bbox
string
Viewport bounds west,south,east,north. Omit for everything (capped).
curl -s "https://navvo.io/api/v1/road-edits/geojson?bbox=35.8,31.9,36.0,32.0" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "LineString", "coordinates": [[35.911, 31.954], [35.912, 31.955]] },
      "properties": {
        "id": "", "layerType": "road_edits", "editType": "closure", "geometryType": "line",
        "name": "Rainbow St closed", "reason": "construction", "status": "active",
        "severity": 4, "blocksRouting": true,
        "startsAt": null, "endsAt": "2026-07-01T18:00:00.000Z", "permanent": false,
        "color": "#DC2626"
      }
    }
  ],
  "metadata": { "layerType": "road_edits", "name": "Road edits", "source": "navvo-road-edits", "hasData": true }
}
PropertyNotes
editTypeclosure · restriction · custom_road · attribute
geometryTypeline · polygon · point
blocksRoutingwhen true, routing detours around this edit
permanent / startsAt / endsAtvalidity window (permanent: true ⇒ no end)
colorsuggested render colour for the edit type
custom_road edits are map annotations — they are drawn on the map but are not routable (the routing engine drives a prebuilt graph; a new drivable road needs a graph rebuild). Closures, restrictions, and adjustments take effect immediately.
Copyright © 2026