Skip to main content

Consent-Based Location Monitoring

The business problem​

Background location tracking is only legitimate — and only usable as evidence in a dispute — if consent is captured, scoped, and revocable correctly, and if the trail proving all of that is itself auditable. This guide covers the parts of Location Monitoring that are about governance, not mechanics: what consent actually authorizes, how long data lives, who can access it, and what gets logged.

What AfriHex returns​

The full consent lifecycle is five distinct calls, not one:

StageEndpointWhat it does
CapturePOST /v2/consent/grantRecords consent, scope, purpose, and an expiry
CheckGET /v2/consent/statusCurrent state — active, scope, purpose, granted/expiry timestamps
RevokePOST /v2/consent/revokeStops future collection immediately — does not delete history
ErasePOST /v2/consent/delete-dataDeletes already-collected pings and drift events on request — requires consent already revoked
AuditGET /v2/banking/audit-logYour account's own access trail — who called what, when

Before you begin​

  • Decide scope (what's collected — defaults to background_location) and purpose (why — see below) before you capture consent, not after. Both are part of what the customer is agreeing to.
  • Know that consent/revoke and consent/delete-data are two separate actions with different effects — see Revocation vs. deletion below. A customer asking to "stop tracking me" wants the former; a customer invoking a right to erasure wants both, in order.
  • Tenant-scoped monitoring endpoints require an account-scoped API key — legacy keys get 403 ACCOUNT_KEY_REQUIRED. See Authentication.

Copyable request​

Capturing consent with an explicit purpose (not just a scope):

curl -X POST "https://api.afrihex.com/v2/consent/grant" \
-H "X-API-Key: $AFRIHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_123",
"loan_id": "loan_456",
"scope": "background_location",
"purpose": "loan_collections",
"legal_document_hash": "sha256-of-signed-consent",
"consent_token": "tok_...",
"duration_days": 365
}'

Full example response​

{
"success": true,
"data": {
"consent_id": "consent_…",
"customer_id": "cust_123",
"loan_id": "loan_456",
"scope": "background_location",
"purpose": "loan_collections",
"granted_at": "2026-09-02T13:49:32Z",
"expires_at": "2027-09-02T13:49:32Z",
"active": true
}
}

Field-by-field explanation​

  • scope — what data category is collected (background_location today). This is a data-minimization control: it names the category, it doesn't itself limit precision or frequency (that's ping scheduling).
  • purpose — why it's collected: loan_collections, fleet_dispatch, delivery_tracking, safety_monitoring, or unspecified (default). Separate axis from scope on purpose — using data collected under loan_collections consent for a different purpose (e.g. marketing analytics) isn't something the customer agreed to, even though the scope is technically the same. Surfaced back on GET /v2/consent/status so you can audit what you told the customer against what you're actually doing with it.
  • consent_token — the credential every subsequent ping must carry. Treat it like a bearer credential scoped to one customer/loan, not a public identifier.
  • expires_at — consent isn't indefinite by default (365 days). Plan for re-consent, not silent expiry-driven data gaps — see Re-verification scheduling for the parallel concept on the KYC side.

Revocation vs. deletion​

Two different customer requests, two different calls:

  • "Stop tracking me." → POST /v2/consent/revoke. Stops future pings and drift checks immediately. Historical pings and drift events already collected are untouched — they still exist, subject to the normal retention window.
  • "Delete what you've collected about me." → POST /v2/consent/delete-data, after revoking. This erases collected pings and drift events immediately instead of waiting out the scheduled retention job. It requires consent to already be revoked (400 otherwise) — by design, so a live monitoring relationship can never be wiped out from under itself.
  • Neither call touches KYC verifications or signed certificates — those carry their own retention mandate (see Identity & KYC — Compliance notes) and are never subject to self-service deletion through the monitoring API.
curl -X POST "https://api.afrihex.com/v2/consent/revoke" \
-H "X-API-Key: $AFRIHEX_API_KEY" -H "Content-Type: application/json" \
-d '{ "customer_id": "cust_123", "loan_id": "loan_456" }'

curl -X POST "https://api.afrihex.com/v2/consent/delete-data" \
-H "X-API-Key: $AFRIHEX_API_KEY" -H "Content-Type: application/json" \
-d '{ "customer_id": "cust_123", "loan_id": "loan_456" }'
{
"success": true,
"data": { "customer_id": "cust_123", "loan_id": "loan_456", "pings_deleted": 214, "drift_events_deleted": 3 }
}

The tracking-session lifecycle​

There's no separate "session" object — the lifecycle is implicit in the consent + ping + schedule relationship:

  1. Consent is granted with an expires_at and a consent_token.
  2. The device reports pings (POST /v2/location/ping) carrying that token — at whatever cadence POST /v2/monitoring/schedule sets (2h/6h/daily/weekly).
  3. A missed cadence (device off, no GPS) is reported as a heartbeat (source: "none", lat/lng of 0) rather than silence — this is how "going dark" gets flagged distinctly from "hasn't moved."
  4. The session ends at expires_at, on consent/revoke, or when the loan itself closes — whichever comes first. There's no separate session-close call; it follows consent state.

Device identifiers and access control​

  • /v2/location/ping does not carry a device identifier. It's scoped by customer_id + loan_id + consent_token only — AfriHex's monitoring layer doesn't itself correlate pings to a specific physical device. device_id exists as an optional field on POST /v2/kyc/verify and POST /v2/verify/proximity instead, for fraud correlation at verification time (see Identity & KYC) — don't assume it's tracked on every ping just because it's tracked at onboarding.
  • Access control is per-tenant, not per-key. Monitoring endpoints require an account-scoped key; a 403 naming another account's loan means exactly what it says — resources are tenant-isolated, not just permission-gated.

Error and edge cases​

  • consent/delete-data returns 400. Consent is still active — revoke it first. This ordering is enforced server-side, not just documented convention.
  • A ping arrives after expires_at. Treat consent expiry as a hard stop in your own client too, not just server-side enforcement — don't rely on the API to silently reject late pings as your only safeguard.
  • purpose omitted on an old integration. Defaults to unspecified rather than rejecting the request — existing integrations built before this field existed keep working, but you should backfill a real purpose as you touch each flow.
  • A customer's consent is active but their loan has since closed. Nothing automatically revokes consent when a loan closes — that's your application's responsibility to call consent/revoke (and, if appropriate, consent/delete-data) as part of loan closure.

Production checklist​

  • Every consent grant records a real purpose, not the unspecified default, once you've migrated off older integration code.
  • Loan/relationship closure in your system triggers consent/revoke automatically — it's not a manual, easy-to-forget step.
  • A customer-facing "delete my data" request calls revoke then delete-data, in that order, and you handle the 400 if revoke hasn't propagated yet.
  • GET /v2/banking/audit-log is reviewed periodically, not only pulled reactively when a regulator asks.
  • Nothing outside the monitoring/KYC pipeline reads raw ping history for a purpose the customer didn't consent to — see Using Risk Scores Responsibly for why this matters even when the data is technically accessible to you.
  • Location Monitoring — the full ping/drift/geofence/webhook mechanics this guide's governance layer sits on top of.
  • Using Risk Scores Responsibly — what not to infer from the location data this consent authorizes collecting.
  • Webhook Security — securing the drift/ geofence_breach/consent_revoked events this flow produces.