Skip to main content

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-token mints a short-lived, single-use code; the recipient redeems it at POST /redeem into a pairing tied to their own account. GET /viewers / GET /watching list 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 /checkin reports your own location (identity is the account, not the device — logging in on any phone updates it), and GET /{targetId}/location returns 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/create accepts fence_type polygon or isochrone (drive-time contour), not just circle — a lender's actual collection catchment shape instead of an oversized circle, while keeping the same customer_id/loan_id tagging and automatic geofence_breach webhook on ping ingestion that circle fences already had. Under the hood these are stored as the same H3 cell-cover representation POST /v2/service-area uses, so a breach check costs the same regardless of shape.

2026-09-01 — v5.14.0​

  • Landmark narration confidence + alternates — when narration is landmark or both, each step's instruction_landmark now comes with landmark_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) and alternate_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}/report lets 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 as POST /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-data erases a customer's collected location pings and drift events immediately, instead of waiting out the scheduled retention window. Distinct from POST /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/grant accepts a purpose field (loan_collections / fleet_dispatch / delivery_tracking / safety_monitoring / unspecified), separate from scope. scope describes what data is collected; purpose describes why. Optional — omitting it defaults to unspecified, so existing integrations are unaffected. Surfaced back on GET /v2/consent/status.
  • Webhook replay protection — every webhook delivery now also carries X-Webhook-Timestamp and X-Webhook-Signature-V2 (HMAC over "{timestamp}." + payload, Stripe's convention) alongside the existing X-Webhook-Signature. X-Webhook-Signature alone 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-Signature is 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 provenance object: source (device_gps / geocoded_text / third_party_match / user_confirmed / agent_verified), provider, accuracy_meters, confidence, and verified_at. This is a different axis from any confidence/quality_score/precision you're already reading — those measure data completeness or spatial exactness, provenance.source tells you how the point was actually established, so a geocoded guess is never mistaken for verified evidence. Live on GET /v2/lookup, GET /v2/reverse, GET /v2/address/resolve, GET /v2/landmarks/geocode, POST /v2/pod/confirm (part of the signed receipt itself), and POST /v2/verify/proximity.
  • Retail density (Enterprise tier) — GET /v2/analytics/retail-density?bbox=north,south,east,west returns 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 get 403 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 annotating steps[].traffic_factor on POST /v2/route.

2026-08-28 — v5.11.0​

  • Crowdsourced road-hazard reports — GET/POST /v2/route/incidents let 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). New avoid_incidents boolean on POST /v2/route gives 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 carry incident_count and fold nearby reports into warnings regardless 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, and POST|GET|DELETE /v2/verify/schedule* now require an account to be granted Banking Suite access (see Authentication → Banking Suite access); an ungranted account gets 403 BANKING_ACCESS_REQUIRED. Access is set up per institution — talk to us if you're integrating one of these. POST /v2/kyc/verify and POST /v2/verify/proximity are 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_check in KYC and proximity-verify responses carries degraded and degraded_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. A degraded: true result 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/transit used 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 carries walk_only, and the response carries no_transit (set when nothing uses a vehicle, including an empty result) plus a note. 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_transit is set and the miss looks like a clock problem rather than a routing gap, note is now backed by real GTFS data: first_trip / last_trip name 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 malformed date/time now returns 400 INVALID_PARAM instead of a misleading 503.
  • "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/route opened to the public tier — the turn-by-turn feed a nav client (Ferrostar) consumes right after planning a route no longer requires an X-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/alerts returns 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-forecast returns 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,lng renders 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/route responses and each alternatives[] entry now carry recommended (true when a non-fastest, safer route wins), recommend_reason ("avoids 2 flood-prone areas"), rain_note, rain_eta_penalty_s, flood_crossings, and has_unpaved / unpaved_distance_m. Absent has_unpaved means "unknown" (fully paved OR surface enrichment didn't run).
  • Travel modes — okada added as an alias of motor_scooter (motorbike routing); omitting mode (or passing "") also defaults to driving.
  • Transit — modes is now a case-insensitive substring selector (empty or containing "transit" enables transit routing); max_walk_m is accepted but currently ignored. Transit legs now carry the decoded geometry ([lng, lat] pairs) plus intermediate stops (new TransitStop schema) so maps can draw the exact leg path.
  • Navigation arrival is fail-open — every field on POST /v2/navigation/arrival is optional; missing or zero coordinates are silently dropped (204), never a 400.
  • Address resolve — structure-precision points on GET /v2/address/resolve now include label and last_seen_at, and the response gains a meta block.

2026-08-10 — v5.7.0​

  • Lane guidance — route steps now carry a lanes array ("keep left of 3 lanes") decoded from Valhalla's turn-lane bitmask (indications/valid/ active). Only present where the road graph has turn:lanes OSM data; a Ghana extract check found lanes on 104k ways but turn:lanes on 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, and opening_hours (sourced from OSM tags) on landmarks/geocode, /v2/route/along, and route landmarks_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,west returns landmarks whose centroid falls inside the rectangle (same ordering as /v2/map/tiles), so map POI dots render across the visible viewport.
  • has_photo filter — GET /v2/landmarks/geocode?near=…&has_photo=true returns only landmarks with a resolved photo.
  • Landmark photos — photo_url (Wikimedia Commons thumbnail) is now returned on landmarks/geocode, landmarks/around, hexcode/{code}/landmarks, /v2/route/along, and route landmarks_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 — RouteStep now carries bearing_before, bearing_after, turn_angle, turn_class, per-step coordinates, and the surface / surface_color pair, plus verbal_alert and verbal_post voice prompts.

2026-08-08 — v5.6.1​

  • Mobile Google sign-in — POST /v2/auth/google/mobile verifies 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/password attaches a password to an OAuth-only account or changes an existing one, enabling "log in either way".
  • Forgot / reset password — POST /v2/auth/forgot-password emails 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-password consumes it.
  • Password policy — minimum length lowered 15 → 8, common passwords blocked.

2026-08-08 — v5.6.0​

  • Live traffic — GET /v2/route/traffic returns 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/transit plans 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/arrival is 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/search now returns a did_you_mean suggestion when the query almost matches a known place.
  • Route responses — RouteStep now carries traffic_factor, traffic_severity, and traffic_color so clients can colorize route lines.
  • Admin — GET /v2/admin/traffic/accuracy reports 14-day MAPE for both ETA models (static vs learned) with a learned_wins gate that decides the default.

2026-07-10 — v5.5.0​

  • Ghanaian-language services — POST /v2/language/translate (English ↔ Twi/Ewe/Ga/Dagbani/Fante/Frafra) and POST /v2/language/transcribe (Ghanaian-language speech-to-text), proxying GhanaNLP Khaya. Public but throttled; unconfigured deployments return 503 LANGUAGE_QUOTA.

2026-07-10 — v5.4.1​

  • Smarter address parsing — POST /v2/address/parse now recognises every GPS-code shape (AO-K452-3583, compact AOK4523583), extracts codes pasted with trailing text, and returns a code field so callers look up the code, not the raw query.

2026-07-06 — v5.4.0​

  • Self-hosted basemaps — GET /v2/tiles/{name} serves .pmtiles vector 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), with profiles/kenya.json as a worked example.
  • Pluggable addressing — the addressing backend (GhanaPostGPS upstream by default) is a swappable ADDRESS_PROVIDER seam; none runs 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.