Skip to main content

Route a Driver to the Correct Entrance

The business problem​

"Route me to this hex code" and "drop the driver at the customer's actual gate" are different requests, and treating them as the same one is how a delivery ends at the wrong side of a walled compound or a divided highway. This guide explains exactly what POST /v2/route snaps a destination to, what it doesn't do automatically, and how to get a genuinely precise arrival point when the default isn't good enough.

What AfriHex returns​

Four distinct concepts, easy to conflate:

ConceptWhat it isWhere it comes from
Destination pinWhatever coordinate or hex code you passed as toYour request
Hex centroidThe mathematical center of the destination's hex cellPure H3 math — always available, never evidence of an actual entrance
Road-access pointWhere the routed path actually meets a drivable road, corrected for which side of a divided road the destination is onValhalla's road-network snap, adjusted by heading
Surveyed entranceA confirmed door/gate for this exact hex, if one's been mappedGET /v2/address/resolve?hex=…'s structure precision tier

POST /v2/route's own destination-snapping logic is a two-way choice, not the full three-tier hierarchy: passing hex snaps to a surveyed structure point when one exists, else the hex centroid — it does not fall back to building_edge footprint-snapping the way GET /v2/address/resolve does. See Hex Addressing — five things that aren't the same for the full three-tier breakdown.

Before you begin​

  • Know whether your destination hex has a surveyed structure point. If it doesn't, routing will arrive at a mathematical centroid, which can be off-road or on the wrong side of a building in dense areas.
  • If you need better than "structure point or centroid," resolve the destination yourself first (GET /v2/address/resolve?hex=…) and pass the resulting coordinate as point, not hex, so you control exactly which precision tier you're routing to.
  • On divided roads (Ring Road, N1, any dual carriageway), have a heading if you can get one — otherwise the endpoint may snap to the far carriageway and open the route with a phantom U-turn.

Copyable request​

Routing straight to a hex code — accepting whatever precision is available:

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-0GXTJJB0ZZZZZ", "heading": 180 },
"mode": "driving"
}'

Resolving precision yourself first, then routing to an exact point:

curl "https://api.afrihex.com/v2/address/resolve?hex=AF-GH-7-0GXTJJB0ZZZZZ" \
-H "X-API-Key: $AFRIHEX_API_KEY"
{
"success": true,
"data": {
"hex": "AF-GH-7-0GXTJJB0ZZZZZ",
"point": { "lng": -0.1867, "lat": 5.604 },
"precision": "structure",
"confidence": 85,
"label": "main gate"
}
}
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": { "point": { "lng": -0.1867, "lat": 5.604 }, "heading": 180 },
"mode": "driving"
}'

Full example response​

{
"success": true,
"data": {
"distance_m": 4604,
"duration_s": 687.079,
"eta_s": 1122.7864,
"coordinates": [ [-0.195223, 5.604169], [-0.1867, 5.604] ],
"steps": [
{
"instruction": "Turn right onto the destination gate.",
"name": "unnamed access road",
"distance_m": 32,
"turn_class": "right"
}
]
}
}

Field-by-field explanation​

  • to.hex vs. to.point — sending hex delegates the precision decision to AfriHex (structure point if surveyed, else centroid); sending point gives you full control, at the cost of an extra call if you want anything better than the raw centroid.
  • heading — a compass bearing (0–359, 0 = north) for the endpoint, not the route. It exists specifically so a dual-carriageway destination snaps to the correct side instead of routing the driver past it and around.
  • radius_m — the road-search radius (Valhalla default ~35m) for snapping a raw point onto the nearest drivable road. Widen it for a destination that's genuinely set back from any mapped road.
  • precision (from address/resolve, not from route itself) — structure (surveyed), building_edge (footprint-inferred), or hex_centroid (no evidence at all) — read this before you route if the delivery is high-value enough to justify the extra call.

Error and edge cases​

  • The route arrives at an obviously wrong spot in a dense area. Almost always a hex_centroid result — no structure point exists for that cell. This isn't a routing bug; it's the absence of survey data. Consider promoting a structure point (POST /v2/admin/structure-points/promote) the first time a driver manually confirms the real gate, so future routes to the same hex improve.
  • The route opens with an immediate U-turn. Classic missing-heading symptom on a divided road — the snap picked the wrong carriageway. Add heading from the vehicle's compass, or from the bearing of the previous route leg if this is a multi-stop run.
  • from/to reject with a validation error. You sent both hex and point on the same endpoint — supply exactly one, never both (see Route endpoints).
  • A structure point exists but still looks off. Check last_seen_at on the address/resolve response — a structure point surveyed years ago at a since-redeveloped site can be stale; there's no automatic expiry.

Production checklist​

  • High-value or last-mile-sensitive deliveries call GET /v2/address/resolve?hex=… and check precision before routing, rather than always routing straight to hex.
  • heading is passed whenever you have it — GPS bearing, previous leg's direction, or a stored value from a prior successful delivery to the same point.
  • A driver's manual correction ("actual gate is here, not where the app pointed") has a path back into POST /v2/admin/structure-points/promote, so the fix compounds instead of repeating every delivery.
  • UI clearly distinguishes "we know exactly where this is" (structure) from "this is our best guess" (hex_centroid) rather than showing one generic pin style for both.