Changelog
All notable changes to the AfriHex API. The API is versioned at /v2/* — this
lists product-level changes, not every internal fix.
2026-09-11 — v5.16.0
- Partner Locator — a new consumer "find my partner" feature under
/v2/locator/*:POST /share-tokenmints a short-lived, single-use code; the recipient redeems it atPOST /redeeminto a pairing tied to their own account.GET /viewers/GET /watchinglist who can see you and who you can see;DELETE /viewers/{pairingId}revokes one person without touching anyone else you've shared with — the fix for the obvious single-shared-ID design, which can't revoke one person without regenerating for everyone.POST /checkinreports your own location (identity is the account, not the device — logging in on any phone updates it), andGET /{targetId}/locationreturns a paired target's last-known position. See the Partner Locator guide.
2026-09-01 — v5.15.0
- Polygon and isochrone geofences —
POST /v2/geofence/createacceptsfence_typepolygonorisochrone(drive-time contour), not justcircle— a lender's actual collection catchment shape instead of an oversized circle, while keeping the samecustomer_id/loan_idtagging and automaticgeofence_breachwebhook on ping ingestion that circle fences already had. Under the hood these are stored as the same H3 cell-cover representationPOST /v2/service-areauses, so a breach check costs the same regardless of shape.
2026-09-01 — v5.14.0
- Landmark narration confidence + alternates — when
narrationislandmarkorboth, each step'sinstruction_landmarknow comes withlandmark_confidence(0.0–1.0 — how well-documented the referenced landmark is, not how sure the match itself is — don't present it as certain when this is low) andalternate_landmarks(runner-up landmark names close enough to plausibly be confused with the chosen one; empty when there's no real ambiguity). - Report a wrong landmark —
POST /v2/landmarks/{slug}/reportlets anyone flag that a landmark is wrong for turn-by-turn narration (wrong_landmark/wrong_side/landmark_gone/other). No API key, no admin queue — same posture asPOST /v2/route/incidents. Reports reinforce rather than duplicate, and once a landmark accumulates enough corroborated reports it's automatically excluded from narration candidate selection until reviewed — general landmark search, geocoding, and POI density are unaffected.
2026-09-01 — v5.13.0
- On-demand data deletion —
POST /v2/consent/delete-dataerases a customer's collected location pings and drift events immediately, instead of waiting out the scheduled retention window. Distinct fromPOST /v2/consent/revoke, which only stops future collection. Requires consent to already be revoked (400 otherwise) — revoke first, then delete. Deliberately never touches KYC verifications or certificates, which carry their own retention mandate. - Purpose limitation on consent —
POST /v2/consent/grantaccepts apurposefield (loan_collections/fleet_dispatch/delivery_tracking/safety_monitoring/unspecified), separate fromscope.scopedescribes what data is collected;purposedescribes why. Optional — omitting it defaults tounspecified, so existing integrations are unaffected. Surfaced back onGET /v2/consent/status. - Webhook replay protection — every webhook delivery now also carries
X-Webhook-TimestampandX-Webhook-Signature-V2(HMAC over"{timestamp}." + payload, Stripe's convention) alongside the existingX-Webhook-Signature.X-Webhook-Signaturealone never expired, so a captured signed payload could be replayed indefinitely; verifying V2 and rejecting deliveries where the timestamp is more than ~5 minutes stale closes that gap.X-Webhook-Signatureis unchanged and still sent on every delivery — this is purely additive, adopt V2 whenever convenient. See Webhooks → Replay protection for verification examples.
2026-09-01 — v5.12.0
- Address provenance — every coordinate-returning response now carries a
provenanceobject:source(device_gps/geocoded_text/third_party_match/user_confirmed/agent_verified),provider,accuracy_meters,confidence, andverified_at. This is a different axis from anyconfidence/quality_score/precisionyou're already reading — those measure data completeness or spatial exactness,provenance.sourcetells you how the point was actually established, so a geocoded guess is never mistaken for verified evidence. Live onGET /v2/lookup,GET /v2/reverse,GET /v2/address/resolve,GET /v2/landmarks/geocode,POST /v2/pod/confirm(part of the signed receipt itself), andPOST /v2/verify/proximity. - Retail density (Enterprise tier) —
GET /v2/analytics/retail-density?bbox=north,south,east,westreturns per-hex retail counts (shops, markets, supermarkets, malls, mobile-money agents) as GeoJSON — informal-retail density for FMCG distribution planning and market-potential scoring. Requires an Enterprise-tier API key; other tiers get403 TIER_REQUIRED. - Traffic congestion heatmap —
GET /v2/analytics/traffic-heatmap?bbox=...returns the specific hex cells that have earned their own learned congestion factor from real completed-trip data — a chronically slow junction (Madina Zongo Junction, Circle, Kaneshie Market) now shows up on its own, instead of sharing one number with every other road of its class citywide. Feeds the same learned-traffic loop already annotatingsteps[].traffic_factoronPOST /v2/route.
2026-08-28 — v5.11.0
- Crowdsourced road-hazard reports —
GET/POST /v2/route/incidentslet a driver see and report accident/flooding/road_blocked/police hazards on the map; no account or review needed, reports go live immediately and expire on a kind-specific TTL (2–24h for accident/flooding/road_blocked/police respectively). Newavoid_incidentsboolean onPOST /v2/routegives light rerouting around corroborated (2 or more reports) flooding/road_blocked reports only — a single report, and accident/police reports at any corroboration level, are always warn-only. Route responses now also carryincident_countand fold nearby reports intowarningsregardless of the flag.
2026-08-26 — v5.10.0
- Banking Suite access is now explicitly provisioned, not implicit in any
API key —
POST /v2/collections/register,/collections/bulk-register,/collections/locate,POST /v2/analytics/portfolio-risk, andPOST|GET|DELETE /v2/verify/schedule*now require an account to be granted Banking Suite access (see Authentication → Banking Suite access); an ungranted account gets403 BANKING_ACCESS_REQUIRED. Access is set up per institution — talk to us if you're integrating one of these.POST /v2/kyc/verifyandPOST /v2/verify/proximityare not affected — they stay open to any authenticated account, since they're shared with the general-purpose Address Verify widget. - Optional per-account IP allowlist — accounts with Banking Suite access
can also have an IP allowlist (exact IPs or CIDR ranges) enforced on the
same set of endpoints; a request from outside it gets
403 IP_NOT_ALLOWED. GET /v2/banking/audit-log— a bank's own access history for its Banking Suite usage (who called what, when, from where), scoped to the calling account. The platform-wide log admins see was already there (GET /v2/admin/audit); this is the same idea, self-service.- Fraud checks now say when they're degraded —
fraud_checkin KYC and proximity-verify responses carriesdegradedanddegraded_checks. The underlying velocity / IP-bulk / device-bulk / synthetic-identity sub-checks fail open on a transient error (a DB blip doesn't block a legitimate verification) — but that used to be invisible. Adegraded: trueresult means fewer signals ran than usual, not that nothing suspicious was found.
2026-08-13 — v5.9.0
- Transit said "no service" honestly —
POST /v2/route/transitused to pass an OTP walk-only fallback straight through, so a query with no real transit option (e.g. Achimota → 37 Hospital at 05:00) came back as a 91-minute walk captioned as a trotro trip. Each itinerary now carrieswalk_only, and the response carriesno_transit(set when nothing uses a vehicle, including an empty result) plus anote. The walk itself is still returned — for two points a few hundred metres apart it's the right answer. - First and last trotro of the day — when
no_transitis set and the miss looks like a clock problem rather than a routing gap,noteis now backed by real GTFS data:first_trip/last_tripname the earliest/latest boardable departure near the start point ("too late — the last trotro … was the 102B from Terminal Madina Station at 19:40, already gone"). A malformeddate/timenow returns400 INVALID_PARAMinstead of a misleading503. - "What leaves from here?" (public) —
GET /v2/transit/departures?lat=&lng=&radius_m=answers the question a rider has while standing at a station: which trotro/bus lines can be boarded here, and where does each one go? Lines that only terminate at the stop are excluded, so a 12-route list of mostly noise becomes the handful genuinely boardable. POST /v2/navigate/routeopened to the public tier — the turn-by-turn feed a nav client (Ferrostar) consumes right after planning a route no longer requires anX-API-Key, closing the gap where a logged-out user could plan a trip but hit a login wall the moment they pressed Navigate.
2026-08-11 — v5.8.0
- Weather endpoints (public) —
GET /v2/weather/alertsreturns the in-effect official GMet heavy-rain / flash-flood CAP alerts as a GeoJSON FeatureCollection (event / severity / urgency / certainty, headline + instruction, expiry);GET /v2/precipitation-forecastreturns the next-6-hour rain-ahead forecast as a GeoJSON point cloud (~165 points over Ghana, max chance of rain % and expected mm, ordered by probability). No auth required. - Static route maps (public) —
GET /v2/route/static?from=lat,lng&to=lat,lngrenders the computed route as a fixed 800x500 PNG (blue route line, green start pin, red end flag, numbered amber landmark pins, legend overlay). IP-throttled (15/min) — the Geoapify key stays server-side. - Safer-route flags —
POST /v2/routeresponses and eachalternatives[]entry now carryrecommended(true when a non-fastest, safer route wins),recommend_reason("avoids 2 flood-prone areas"),rain_note,rain_eta_penalty_s,flood_crossings, andhas_unpaved/unpaved_distance_m. Absenthas_unpavedmeans "unknown" (fully paved OR surface enrichment didn't run). - Travel modes —
okadaadded as an alias ofmotor_scooter(motorbike routing); omittingmode(or passing"") also defaults todriving. - Transit —
modesis now a case-insensitive substring selector (empty or containing"transit"enables transit routing);max_walk_mis accepted but currently ignored. Transit legs now carry the decodedgeometry([lng, lat]pairs) plus intermediatestops(newTransitStopschema) so maps can draw the exact leg path. - Navigation arrival is fail-open — every field on
POST /v2/navigation/arrivalis optional; missing or zero coordinates are silently dropped (204), never a 400. - Address resolve — structure-precision points on
GET /v2/address/resolvenow includelabelandlast_seen_at, and the response gains ametablock.
2026-08-10 — v5.7.0
- Lane guidance — route steps now carry a
lanesarray ("keep left of 3 lanes") decoded from Valhalla's turn-lane bitmask (indications/valid/active). Only present where the road graph hasturn:lanesOSM data; a Ghana extract check foundlaneson 104k ways butturn:laneson just 23 — so the plumbing is live but most routes won't show lanes until OSM improves. - POI contact details — landmarks now return
phone,website, andopening_hours(sourced from OSM tags) onlandmarks/geocode,/v2/route/along, and routelandmarks_passed, so POI detail cards can show contact info next to name and kind. - Viewport bbox landmark search —
GET /v2/landmarks/geocode?bbox=north,south,east,westreturns landmarks whose centroid falls inside the rectangle (same ordering as/v2/map/tiles), so map POI dots render across the visible viewport. has_photofilter —GET /v2/landmarks/geocode?near=…&has_photo=truereturns only landmarks with a resolved photo.- Landmark photos —
photo_url(Wikimedia Commons thumbnail) is now returned onlandmarks/geocode,landmarks/around,hexcode/{code}/landmarks,/v2/route/along, and routelandmarks_passed. The photo matcher also gained a Commons search fallback reaching ~130 landmarks; map photo cards are deferred until matching is geo-verified, so treat photos as illustrative. - Step maneuvers —
RouteStepnow carriesbearing_before,bearing_after,turn_angle,turn_class, per-stepcoordinates, and thesurface/surface_colorpair, plusverbal_alertandverbal_postvoice prompts.
2026-08-08 — v5.6.1
- Mobile Google sign-in —
POST /v2/auth/google/mobileverifies a Google ID token server-side (aud accepted from both web and mobile client IDs) and issues an app token with no web redirect, so it works on Android / iOS. - Passwords —
POST /v2/me/passwordattaches a password to an OAuth-only account or changes an existing one, enabling "log in either way". - Forgot / reset password —
POST /v2/auth/forgot-passwordemails a one-time, hashed, 30-minute reset token (via Brevo) and returns a generic response so email addresses can't be enumerated;POST /v2/auth/reset-passwordconsumes it. - Password policy — minimum length lowered 15 → 8, common passwords blocked.
2026-08-08 — v5.6.0
- Live traffic —
GET /v2/route/trafficreturns current congestion per road class (motorway, primary, secondary, residential) with the effective traffic multiplier — learned from real trips where the hourly loop has ≥30 samples, else the static Accra table — plus a severity label and hex color for UI tinting. - Transit routing —
POST /v2/route/transitplans point-to-point trotro / bus trips on the Accra GTFS network via OTP2, returning up to 3 itineraries with walk and transit legs, stop names, route names, and per-leg times. - Navigation arrival telemetry —
POST /v2/navigation/arrivalis a fire-and-forget signal recording where a navigator ended up vs the pinned destination (an address-accuracy signal) and, with optional origin/elapsed-time fields, captures a traffic sample that calibrates route ETAs. - Did-you-mean search —
/v2/searchnow returns adid_you_meansuggestion when the query almost matches a known place. - Route responses —
RouteStepnow carriestraffic_factor,traffic_severity, andtraffic_colorso clients can colorize route lines. - Admin —
GET /v2/admin/traffic/accuracyreports 14-day MAPE for both ETA models (static vs learned) with alearned_winsgate that decides the default.
2026-07-10 — v5.5.0
- Ghanaian-language services —
POST /v2/language/translate(English ↔ Twi/Ewe/Ga/Dagbani/Fante/Frafra) andPOST /v2/language/transcribe(Ghanaian-language speech-to-text), proxying GhanaNLP Khaya. Public but throttled; unconfigured deployments return503 LANGUAGE_QUOTA.
2026-07-10 — v5.4.1
- Smarter address parsing —
POST /v2/address/parsenow recognises every GPS-code shape (AO-K452-3583, compactAOK4523583), extracts codes pasted with trailing text, and returns acodefield so callers look up the code, not the raw query.
2026-07-06 — v5.4.0
- Self-hosted basemaps —
GET /v2/tiles/{name}serves.pmtilesvector basemap archives for the map view, plus a downloadable "Ghana for offline" extract.
Earlier highlights
- Country profiles — the geocoding stack can be re-targeted to another
African country via a single profile file (
COUNTRY_PROFILE), withprofiles/kenya.jsonas a worked example. - Pluggable addressing — the addressing backend (GhanaPostGPS upstream by
default) is a swappable
ADDRESS_PROVIDERseam;noneruns hex-only deployments with no upstream. - Passive location monitoring — consent, background pings, drift detection, geofences, webhook alerts with retries, and per-tenant isolation.
- Hex engine — lossless Crockford base-32 H3 codes, grid navigation, distance/path, compaction, map tiles, and bulk coding.
- Identity & KYC — address verification with quality scoring, proximity verification with signed Ed25519 certificates, and proof-of-delivery receipts.
- Routing — turn-by-turn routing, distance matrices, isochrones, GPX, and landmark narration powered by self-hosted Valhalla, with road-gap self-healing and flood/rain-aware rerouting.