Navvo
API Reference

Telemetry

Submit anonymous trips to improve traffic, and read aggregated traffic data.

Telemetry

Contribute anonymous GPS trips that Navvo map-matches and aggregates into the live/typical traffic layers, and read back aggregated traffic data. If your app has its own location stream (delivery drivers, ride-hail, fleet), submitting it here makes traffic better for everyone — including your own ETAs.

Scope required: telemetry

Units & coordinates. Trip input points use named { lat, lng } fields; speed is in meters per second; capturedAt is an ISO-8601 timestamp. All traffic output speeds are km/h, and output geometry is GeoJSON [lng, lat].

POST /telemetry/trips

Submit a trip. The trip is stored and queued for asynchronous map-matching (via the Navvo routing engine); the call returns immediately.

Request body

points
array required
Ordered GPS points (see point shape below). Must be non-empty.
userId
string
Optional UUID identifying the contributor. If present, must be a valid UUID.
metadata
object
Free-form. Set metadata.consentCaptured = false to flag a trip as missing consent (it is still accepted but counted in the health summary). Consent is assumed true otherwise.

Each points[] element:

FieldTypeRequiredNotes
latnumberyesLatitude, −90..90.
lngnumberyesLongitude, −180..180.
speednumbernometers/second.
headingnumbernoDegrees.
capturedAtstringnoISO-8601; defaults to now.
Points are validated: lat/lng must be present numbers within range, speed/heading numeric, and a trip carries at most 5000 points. Out-of-range or malformed points return 400 with a validation array.
{
  "userId": "8b1f5c2e-3d4a-4e2b-9f10-7c2a1b6d9e44",
  "metadata": { "consentCaptured": true, "device": "ios-17" },
  "points": [
    { "lat": 31.9500, "lng": 35.9100, "speed": 12.1, "heading": 90, "capturedAt": "2026-05-16T12:00:00Z" },
    { "lat": 31.9512, "lng": 35.9123, "speed": 13.4, "heading": 88, "capturedAt": "2026-05-16T12:00:05Z" }
  ]
}

Response (201)

{ "accepted": true, "tripId": "f0a1c3d5-…", "jobId": "12" }

The trip is processed in the background: matched to the road network, then per-edge observed speeds feed the traffic speed profiles that power the Traffic endpoints. status becomes matched or failed.

Privacy. Submit only data you have consent to share, and prefer anonymizing trip endpoints (trim the first/last few points). Trips power aggregate traffic only — they are not exposed as individual tracks through the API.

POST /telemetry/errors

Report client-side crashes and errors, batched. A lightweight crash-reporting sink for your Navvo-powered apps (web, Android, iOS): send caught exceptions or fatal crashes and Navvo stores them for triage.

Authentication is not required — a crash reporter must never be blocked. If you send a valid Authorization: Bearer <token>, the report is attributed to that verified user; otherwise it is anonymous. A client-supplied user id is never trusted. This route is throttled to 30 requests/min per IP.

Request body

errors
array required
Up to 20 error items (see shape below). Must be non-empty.

Each errors[] element:

FieldTypeRequiredNotes
platformstringyesweb, android, or ios.
messagestringyesError message (max 2000 chars).
stackstringnoStack trace (max 8000 chars).
appVersionstringnoYour app version.
deviceModelstringnoDevice model.
osVersionstringnoOS version.
contextobjectnoFree-form structured context (screen, state, breadcrumbs).
occurredAtstringnoISO-8601 timestamp; defaults to receipt time.
{
  "errors": [
    { "platform": "android", "appVersion": "3.2.1", "deviceModel": "Pixel 8",
      "osVersion": "Android 15", "message": "TypeError: cannot read property 'lat' of null",
      "stack": "at MapView.render (map.js:214)…", "context": { "screen": "navigation" },
      "occurredAt": "2026-07-19T09:20:00Z" }
  ]
}

Response (201)

{ "ok": true, "accepted": 1 }

accepted is the number of stored error rows. Items missing platform/message or exceeding a length cap return 400 with a validation array. Stored reports are retained for a limited window (30 days by default) and then swept.


GET /telemetry/trips

Admin only. This endpoint now requires a signed-in Navvo user with the admin/super_admin role (Bearer JWT); other callers receive 403. It was previously readable in keyless mode and exposed contributor ids and first/last GPS points.

List the most recent trips (no pagination). Each item is a trip with status, consentCaptured, and a routeSummary (point/edge counts and first/last point); the raw points are not included.


GET /telemetry/health

Ingestion quality summary over the most recent 500 trips.

{
  "totalTrips": 500,
  "matchedTrips": 472,
  "failedTrips": 18,
  "consentMissingTrips": 3,
  "sampleRate": 0.944,
  "generatedAt": "2026-06-09T10:15:00.000Z"
}

GET /telemetry/daily

Trip counts bucketed per UTC day over the last 365 days.

[ { "day": "2026-06-09", "trips": 14 }, { "day": "2026-06-08", "trips": 31 } ]

GET /telemetry/traffic-overlay

The aggregated traffic layer as a GeoJSON FeatureCollection of road-edge speed profiles with congestion classification — the data source behind the map traffic layer.

Query parameters

mode
string
current (default; last ~6h) or typical (all-time per-edge averages).
bbox
string
west,south,east,north spatial filter.
limit
string
Max features (capped by zoom; up to 5000).
zoom
string
Drives the limit cap and line generalization.
{
  "type": "FeatureCollection",
  "hasData": true,
  "mode": "current",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "LineString", "coordinates": [[35.911, 31.951], [35.914, 31.952]] },
      "properties": { "edgeId": "e:128374", "congestion": "moderate", "averageSpeedKph": 28.4, "freeFlowSpeedKph": 55, "sampleCount": 4 }
    }
  ],
  "metadata": { "layerType": "traffic", "source": "navvo-telemetry-speed-profiles", "legend": { "light": { "color": "#188038" }, "moderate": { "color": "#D9A441" }, "heavy": { "color": "#D94B4B" }, "blocked": { "color": "#8B1A1A" } } }
}

congestion ∈ light | moderate | heavy | blocked | unknown.

Tiled access

For bounded loading the overlay is also tile-addressed:

EndpointReturns
GET /telemetry/traffic-overlay/tile-coverList of tile URLs covering a bbox (mode, bbox, zoom, maxTiles).
GET /telemetry/traffic-overlay/tiles/{z}/{x}/{y}The overlay for one tile, as GeoJSON.
GET /telemetry/traffic-overlay/vector/{z}/{x}/{y}The overlay for one tile, as a binary vector tile (application/x-protobuf, layer navvo_traffic).
Use the .../vector/{z}/{x}/{y} route to add traffic as a native Navvo Maps vector source; use the GeoJSON tile route if you prefer to style features yourself.
Copyright © 2026