Navvo
API Reference

Transit, Micromobility & Offline

Public-transit stops/routes, bike & scooter stations, journey planning, and offline map regions.

Transit, Micromobility & Offline

Move people the last mile and keep the map alive where the network isn't. This module surfaces Navvo transit feeds (stops and route lines for systems like the Riyadh Metro or the Amman BRT), Navvo micromobility feeds (shared bikes and scooters across the GCC), a multimodal journey planner that stitches walking legs onto a connecting transit route, and offline map regions so the map and search keep working in dead zones — from a packed downtown garage to the open desert of Wadi Rum.

Everything is served and branded by Navvo from a single API. There are no outside services to wire up.

Scope required: places for stops, routes, and stations; routing for journey planning; tiles for offline regions and manifests.

Coordinates are decimal degrees (lat, lng). Distance fields (distanceM) are in metres. A bbox is west,south,east,north. Nearby endpoints accept a radius in metres. Endpoints degrade gracefully — an out-of-coverage viewport returns an empty count:0 collection rather than an error.

GET /transit/stops

Nearby public-transit stops (metro, bus, tram, rail) around a point — the stops you'd draw as markers near the user or use as journey origins. Each stop lists the routeIds that serve it.

curl -s "https://navvo.io/api/v1/transit/stops?lat=24.7136&lng=46.6753&radius=800" \
  -H "x-api-key: nvvo_YOUR_KEY"

Scope required: places

Query parameters

lat
number required
Latitude of the search centre.
lng
number required
Longitude of the search centre.
radius
number
Search radius in metres. Defaults to 500; capped server-side for readability.

Response

FieldTypeDescription
providerstringAlways navvo-transit.
countnumberNumber of stops returned.
stops[]arrayThe nearby stops, nearest first.

Each stops[] element:

FieldTypeDescription
idstringNavvo stop id.
stopIdstringStable feed-level stop identifier (use with the route's routeId).
namestringStop name.
lat / lngnumberStop location.
distanceMnumberDistance from the search centre, in metres.
routeIdsstringIds of the routes that serve this stop.
{
  "provider": "navvo-transit",
  "count": 2,
  "stops": [
    {
      "id": "stop-9a31",
      "stopId": "RYD-METRO-1-OLAYA",
      "name": "Olaya",
      "lat": 24.6913,
      "lng": 46.6857,
      "distanceM": 142,
      "routeIds": ["RYD-METRO-BLUE"]
    },
    {
      "id": "stop-7c08",
      "stopId": "RYD-BUS-300-KINGFAHD",
      "name": "King Fahd Rd",
      "lat": 24.6951,
      "lng": 46.6840,
      "distanceM": 410,
      "routeIds": ["RYD-BUS-300", "RYD-BUS-305"]
    }
  ]
}

GET /transit/routes

Route lines for a viewport — the coloured polylines you overlay on the map to draw a metro or BRT network. Each route carries an encoded shape you can render directly.

curl -s "https://navvo.io/api/v1/transit/routes?bbox=46.55,24.60,46.80,24.80" \
  -H "x-api-key: nvvo_YOUR_KEY"

Scope required: places

Query parameters

bbox
string
Viewport bounds west,south,east,north. Only routes whose shape passes through the box are returned (routes with no geometry are kept).
type
number
Filter by GTFS route_type: 0 tram, 1 metro, 2 rail, 3 bus, 4 ferry, … Each returned route also carries a human typeLabel.
q
string
Case-insensitive filter on the route's short/long name.

The response echoes the active filters ({ type, bbox }). Combine them — e.g. ?bbox=…&type=1 for just the metro lines in view.

Response

FieldTypeDescription
providerstringAlways navvo-transit.
countnumberNumber of routes returned.
routes[]arrayThe route lines (see below).

Each routes[] element:

FieldTypeDescription
idstringNavvo route id.
routeIdstringStable feed-level route identifier (matches stops[].routeIds).
shortNamestringShort label (e.g. Blue, 300).
longNamestringFull route name.
typestringMode: metro, bus, tram, rail, or ferry.
colorstringHex colour for the line.
shapestringEncoded polyline for the route geometry.
{
  "provider": "navvo-transit",
  "count": 1,
  "routes": [
    {
      "id": "route-blue",
      "routeId": "RYD-METRO-BLUE",
      "shortName": "Blue",
      "longName": "Riyadh Metro — Line 1 (Blue)",
      "type": "metro",
      "color": "#1E61F0",
      "shape": "qkn~Eqd}xK}@a@k@e@_@e@"
    }
  ]
}
shape is a standard encoded polyline (precision 5). Decode it to [lat, lng] pairs to draw the line, or hand it to the Navvo Maps renderer as a LineString source.

GET /transit/gbfs

Nearby shared micromobility stations — docked bikes, e-bikes, and scooters across the GCC — with live availability counts. Use it to show riders where they can pick up a vehicle now.

curl -s "https://navvo.io/api/v1/transit/gbfs?lat=25.2048&lng=55.2708&radius=600&type=scooter" \
  -H "x-api-key: nvvo_YOUR_KEY"

Scope required: places

Query parameters

lat
number required
Latitude of the search centre.
lng
number required
Longitude of the search centre.
radius
number
Search radius in metres. Defaults to 500.
type
string
Filter by vehicle type: bike, ebike, or scooter. Omit to return all types.
minBikes
number
Only stations with at least this many vehicles available to pick up. Use minBikes=1 to hide empty stations when a rider wants to grab a vehicle now.
minDocks
number
Only stations with at least this many free docks — for a rider who needs somewhere to return/park. (Dockless feeds report no docks, so these are excluded when minDocks is set.)

Response

FieldTypeDescription
providerstringAlways navvo-micromobility.
filtersobjectThe active filters echoed back: { vehicleType, minBikes, minDocks }.
countnumberNumber of stations returned.
stations[]arrayThe nearby stations, nearest first — each with bikesAvailable / docksAvailable.

Each stations[] element:

FieldTypeDescription
idstringNavvo station id.
namestringStation name.
vehicleTypestringbike, ebike, or scooter.
lat / lngnumberStation location.
bikesAvailablenumberVehicles available to take now.
docksAvailablenumberFree docks to return a vehicle (0 for dockless/free-floating stations).
distanceMnumberDistance from the search centre, in metres.
{
  "provider": "navvo-micromobility",
  "count": 2,
  "stations": [
    {
      "id": "mm-4471",
      "name": "Dubai Marina Walk",
      "vehicleType": "scooter",
      "lat": 25.0805,
      "lng": 55.1403,
      "bikesAvailable": 6,
      "docksAvailable": 0,
      "distanceM": 88
    },
    {
      "id": "mm-4490",
      "name": "JBR Station",
      "vehicleType": "ebike",
      "lat": 25.0789,
      "lng": 55.1340,
      "bikesAvailable": 3,
      "docksAvailable": 9,
      "distanceM": 520
    }
  ]
}

POST /transit/plan

A multimodal journey suggestion: given an origin and destination, Navvo finds a connecting transit route and stitches walking legs onto each end (walk to the boarding stop → ride → walk to the destination). When no useful connection exists, it returns a walking alternative plus the nearest stops at both ends so you can offer a fallback.

curl -s "https://navvo.io/api/v1/transit/plan" \
  -H "x-api-key: nvvo_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "lat": 31.9539, "lng": 35.9106 },
    "to":   { "lat": 31.9870, "lng": 35.8650 }
  }'

Scope required: routing

Request body

from
object required
Origin { lat, lng }.
to
object required
Destination { lat, lng }.

Response — connection found

FieldTypeDescription
providerstringAlways navvo-transit.
foundbooleantrue when a connecting route was found.
legs[]arrayOrdered journey legs: a walk leg, a transit leg, then a walk leg.

A transit leg carries the route it uses (a route object as in /transit/routes) plus the board and alight stops (stop objects as in /transit/stops). walk legs carry their own distance and duration.

{
  "provider": "navvo-transit",
  "found": true,
  "legs": [
    {
      "mode": "walk",
      "from": { "lat": 31.9539, "lng": 35.9106 },
      "to":   { "lat": 31.9551, "lng": 35.9119 },
      "distanceM": 210,
      "durationS": 168
    },
    {
      "mode": "transit",
      "route": {
        "routeId": "AMM-BRT-1",
        "shortName": "BRT 1",
        "longName": "Amman BRT — Sweileh Corridor",
        "type": "bus",
        "color": "#0EA15B"
      },
      "board":  { "stopId": "AMM-BRT-1-ABDALI", "name": "Abdali", "lat": 31.9551, "lng": 35.9119 },
      "alight": { "stopId": "AMM-BRT-1-SWEIFIEH", "name": "Sweifieh", "lat": 31.9860, "lng": 35.8669 },
      "durationS": 720
    },
    {
      "mode": "walk",
      "from": { "lat": 31.9860, "lng": 35.8669 },
      "to":   { "lat": 31.9870, "lng": 35.8650 },
      "distanceM": 240,
      "durationS": 192
    }
  ]
}

Response — no connection

When no connecting route fits, found is false and Navvo returns a reason, a direct walking alternative, and the nearest stops at each end so you can prompt the rider toward transit anyway.

FieldTypeDescription
foundbooleanfalse.
reasonstringWhy no transit journey was returned (e.g. no_common_route, out_of_coverage).
walkAlternativeobjectA direct walking leg { distanceM, durationS }.
nearestOriginStops[]arrayNearest stops to the origin (stop objects).
nearestDestStops[]arrayNearest stops to the destination (stop objects).
{
  "provider": "navvo-transit",
  "found": false,
  "reason": "no_common_route",
  "walkAlternative": { "distanceM": 5400, "durationS": 4320 },
  "nearestOriginStops": [
    { "stopId": "AMM-BUS-26-DOWNTOWN", "name": "Downtown", "lat": 31.9515, "lng": 35.9239, "distanceM": 310 }
  ],
  "nearestDestStops": [
    { "stopId": "AMM-BUS-26-SHMEISANI", "name": "Shmeisani", "lat": 31.9700, "lng": 35.9000, "distanceM": 480 }
  ]
}

GET /offline/regions

The catalogue of predefined, downloadable offline map regions — bounded areas a client can pre-cache so the map keeps working without a network. Use it to present a "Download for offline" picker (a whole country or a city).

curl -s "https://navvo.io/api/v1/offline/regions" \
  -H "x-api-key: nvvo_YOUR_KEY"

Scope required: tiles

Response

FieldTypeDescription
providerstringAlways navvo-offline.
regions[]arrayAvailable offline regions (see below).

Each regions[] element:

FieldTypeDescription
idstringRegion id (use with /offline/regions/{id}/manifest).
namestringEnglish name.
nameArstringArabic name.
bboxnumberBounds as [west, south, east, north].
minZoom / maxZoomnumberZoom range the region is packaged for.
estTilesnumberEstimated number of tiles to download.
estSizeMbnumberEstimated download size in megabytes.
countryCodestringISO country code (e.g. SA, JO, AE).
scopestringcountry or city.
versionstringVersion token — changes whenever the pack is updated. Compare it against a stored download to show "Update available".
{
  "provider": "navvo-offline",
  "regions": [
    {
      "id": "05f81944-b193-4fb2-a61d-af3c96b91af4",
      "name": "Jordan",
      "nameAr": "الأردن",
      "scope": "country",
      "bbox": [34.88, 29.18, 39.30, 33.38],
      "minZoom": 5,
      "maxZoom": 12,
      "estTiles": 3999,
      "estSizeMb": 117,
      "countryCode": "JO",
      "version": "2026-06-25T14:55:16.529Z"
    },
    {
      "id": "d86f0ed5-9821-43cc-af67-e5c8fa0ff429",
      "name": "Palestine",
      "nameAr": "فلسطين",
      "scope": "country",
      "bbox": [34.22, 31.22, 35.57, 32.55],
      "minZoom": 5,
      "maxZoom": 12,
      "estTiles": 446,
      "estSizeMb": 13,
      "countryCode": "PS",
      "version": "2026-06-25T14:55:16.529Z"
    }
  ]
}

GET /offline/regions/{id}/manifest

The download manifest for one region — everything a client needs to pre-cache a complete offline base map: style, vector tiles, fonts (glyphs), icons (sprite), and raster fallbacks. Fetch it after the user picks a region, then enumerate the tiles across bbox × zooms and warm your cache.

curl -s "https://navvo.io/api/v1/offline/regions/{id}/manifest" \
  -H "x-api-key: nvvo_YOUR_KEY"

Scope required: tiles

Response

FieldTypeDescription
providerstringAlways navvo-offline.
regionobjectThe region descriptor (same shape as a /offline/regions entry).
styleUrlstringThe map style URL to cache and render offline.
vectorTileTemplatestringVector tile URL template — expand {z}/{x}/{y} across bbox × zooms.
glyphsobjectFont glyphs needed for offline labels: template ({fontstack}/{range} URL template), fontstacks (the stacks the style uses), and ranges (the Unicode ranges to fetch — Latin + Arabic blocks, so EN and AR labels render offline). Cache every fontstack × range combination.
spriteobjectThe icon sprite atlas: json (index), png, and png2x (hi-DPI) URLs — cache all three.
rasterTemplatesobjectRaster tile templates (standard, satellite) for clients that also want an offline raster/satellite fallback. Optional — the vector map alone renders fully offline.
tilesnumberEstimated count of vector tiles for the full bbox × zoom download.
sizeMbnumberEstimated download size in megabytes.
zoomsobject{ min, max } — the zoom levels to download. The renderer overzooms past max, so deeper zooms still display from the cached tiles.
versionstringPack version token — re-fetch the manifest and compare to offer "Update available".
bboxnumberRegion bounds [west, south, east, north].
notestringCaching guidance for the client.
{
  "provider": "navvo-offline",
  "region": { "id": "", "name": "Jordan", "nameAr": "الأردن", "scope": "country",
              "bbox": [34.88, 29.18, 39.30, 33.38], "minZoom": 5, "maxZoom": 12,
              "estTiles": 3999, "estSizeMb": 117, "countryCode": "JO", "version": "2026-06-25T14:55:16.529Z" },
  "styleUrl": "/api/v1/tiles/style?style=standard",
  "vectorTileTemplate": "/api/v1/tiles/vector/navvo/planet/{z}/{x}/{y}.pbf",
  "glyphs": {
    "template": "/api/v1/tiles/glyphs/navvo/{fontstack}/{range}.pbf",
    "fontstacks": ["Noto Sans Regular", "Noto Sans Bold"],
    "ranges": ["0-255", "256-511", "1536-1791", "1792-2047", "64256-64511", "65024-65279"]
  },
  "sprite": {
    "json": "/api/v1/tiles/sprites/navvo/sprite.json",
    "png": "/api/v1/tiles/sprites/navvo/sprite.png",
    "png2x": "/api/v1/tiles/sprites/navvo/sprite@2x.png"
  },
  "rasterTemplates": {
    "standard": "/api/v1/tiles/raster/standard/{z}/{x}/{y}.png",
    "satellite": "/api/v1/tiles/raster/satellite/{z}/{x}/{y}.png"
  },
  "tiles": 3999,
  "sizeMb": 117,
  "zooms": { "min": 5, "max": 12 },
  "version": "2026-06-25T14:55:16.529Z",
  "bbox": [34.88, 29.18, 39.30, 33.38],
  "note": "Cache vector tiles across bbox × zooms (plus glyphs/sprite above) for a complete offline base map; the map overzooms past the cached level."
}
Offline place search is a client feature, not part of the manifest. The manifest covers the base map only (tiles, style, glyphs, sprite) — it carries no place-search index. The Navvo PWA implements offline place search client-side; if your app needs it, cache your own place data (e.g. recent GET /search / GET /places responses) alongside the map pack.
Manifest URLs are relative and, like all map resources, are fetched directly by the renderer which can't send an x-api-key header — append ?api_key=nvvo_YOUR_KEY when you expand styleUrl and the tile/glyph/sprite templates. See Map Tiles & Styles for details.
Copyright © 2026