Routing & Navigation
Turn-by-turn routing for Ghana's road network, powered by a self-hosted Valhalla engine. Because addresses are sparse in Ghana, routing here understands landmarks — the way people actually navigate.
Route between two points
POST /v2/route accepts hex codes, GPS codes, or coordinates as endpoints:
curl -X POST "https://api.afrihex.com/v2/route" \
-H "X-API-Key: $AFRIHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": { "hex": "AF-GH-7-0GXTQD5RFZZZZ" },
"to": { "hex": "AF-GH-7-0GXTQD5RJ0000" },
"mode": "driving"
}'
Travel modes: driving, walking, cycling. The response includes distance,
duration, a polyline, and turn-by-turn steps:
Request object — POST /v2/route:
| Parameter | Type | Required | Definition |
|---|---|---|---|
from | object | required | Origin — { hex }, { gps_code }, or { lat, lng } |
to | object | required | Destination — same accepted shapes |
mode | string | optional | driving, walking, or cycling (default driving) |
{
"success": true,
"data": {
"distance_m": 4604,
"duration_s": 687.079,
"eta_s": 1122.7864,
"traffic_note": "morning rush",
"coordinates": [ [-0.195223, 5.604169], [-0.195249, 5.604189] ],
"steps": [
{
"instruction": "Drive northwest on Continental Close.",
"verbal_instruction": "Drive northwest on Continental Close. Then Turn left onto Continental Road.",
"verbal_post": "Continue for 300 meters.",
"name": "Continental Close",
"near_landmark": "Roman Ridge",
"distance_m": 308,
"duration_s": 37.063,
"surface": "paved",
"surface_color": "#4CAF50",
"bearing_before": 308,
"bearing_after": 308,
"turn_class": "straight"
}
],
"landmarks_passed": [],
"has_unpaved": true,
"unpaved_distance_m": 1072
}
}
Route-aware conditions
Routing can account for real-world conditions:
- Flood zones — avoid currently flooded areas.
- Weather alerts — official heavy-rain / flash-flood warnings.
- Rain now — penalise routes through heavy rain when a drier option beats the fastest.
- Surface quality — each step reports
surface(paved/unpaved/unknown) and asurface_color(see the#4CAF50/#FF9800values in the response above). The top level also reportshas_unpavedandunpaved_distance_m.
Distance matrices
POST /v2/route/matrix computes all-pairs travel times/distances for many
origins and destinations in one call — perfect for optimising dispatch:
Request object:
| Parameter | Type | Required | Definition |
|---|---|---|---|
sources | array<object> | required | Origins — { hex }, { gps_code }, or { lat, lng } |
destinations | array<object> | required | Destinations — same shapes |
mode | string | optional | driving, walking, or cycling (default driving) |
curl -X POST "https://api.afrihex.com/v2/route/matrix" \
-H "X-API-Key: $AFRIHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sources": [{"hex":"AF-GH-7-0GXTQD5RFZZZZ"}], "destinations": [{"hex":"AF-GH-7-0GXTQD5VFZZZZ"}], "mode": "driving"}'
{
"success": true,
"data": {
"durations": [[687]],
"distances": [[4605]],
"sources": 1,
"destinations": 1
}
}
Isochrones
POST /v2/route/isochrone answers "how far can I get in 30 minutes?" — returns
a reachable area polygon:
Request object:
| Parameter | Type | Required | Definition |
|---|---|---|---|
location | object | required | Origin — { hex }, { gps_code }, or { lat, lng } |
contours | array<object> | required | Reachability rings — { "time_minutes": 15 } (1–120) |
mode | string | optional | driving, walking, or cycling (default driving) |
curl -X POST "https://api.afrihex.com/v2/route/isochrone" \
-H "X-API-Key: $AFRIHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"location": {"hex": "AF-GH-7-0GXTQD5RFZZZZ"}, "contours": [{"time_minutes": 15}, {"time_minutes": 30}], "mode": "driving"}'
The response returns each contour as a styled GeoJSON polygon (drive-time rings). This drives the Service Areas drive-time zones.
Optimized routes
POST /v2/route/optimized solves a multi-stop problem — visit N waypoints in
the best order (traveling-salesman style).
GPX export
POST /v2/route/gpx returns a GPX file you can drop straight into Google Maps /
Garmin / any GPS device. There's also POST /v2/route/match and
POST /v2/route/match/gpx for snapping a GPS track to the road network.
Navigation
POST /v2/navigate/route is the API behind a turn-by-turn navigation flow:
curl -X POST "https://api.afrihex.com/v2/navigate/route" \
-H "X-API-Key: $AFRIHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": { "hex": "AF-GH-7-0GXTQD5RFZZZZ" },
"to": { "hex": "AF-GH-7-0GXTQD5RJ0000" },
"mode": "driving"
}'
POST /v2/navigation/arrival records when a navigator reaches the pin, scoring
destination accuracy over time. There's also a public route endpoint
(POST /v2/route/public, IP-throttled) used by the QR-code navigation flow so
anyone can get directions without an account.
Static map images
GET /v2/route/static renders a route as a shareable map image (route line +
start/end pins) — great for WhatsApp sharing or receipts.
Landmarks
Find places the way Ghanaians describe them:
GET /v2/landmarks/geocode?q=kaneshie%20market— fuzzy landmark search.GET /v2/landmarks/around?lat=...&lng=...&radius=500— landmarks near a point.GET /v2/hexcode/{code}/landmarks— landmarks inside a hex cell.
Route health
GET /v2/route/health reports whether the routing engine's extract is current —
clients can warn when routes may be stale.
SDK
const route = await afrihex.landmarks.geocode({ q: 'kaneshie market' })
console.log(route.matches[0].centroid) // { lat: 5.5641, lng: -0.2335 }
API reference
See Routing & Navigation — API Reference for every endpoint in this group.