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:
| Stage | Endpoint | What it does |
|---|---|---|
| Capture | POST /v2/consent/grant | Records consent, scope, purpose, and an expiry |
| Check | GET /v2/consent/status | Current state — active, scope, purpose, granted/expiry timestamps |
| Revoke | POST /v2/consent/revoke | Stops future collection immediately — does not delete history |
| Erase | POST /v2/consent/delete-data | Deletes already-collected pings and drift events on request — requires consent already revoked |
| Audit | GET /v2/banking/audit-log | Your account's own access trail — who called what, when |
Before you begin
- Decide
scope(what's collected — defaults tobackground_location) andpurpose(why — see below) before you capture consent, not after. Both are part of what the customer is agreeing to. - Know that
consent/revokeandconsent/delete-dataare 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_locationtoday). 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, orunspecified(default). Separate axis fromscopeon purpose — using data collected underloan_collectionsconsent for a different purpose (e.g. marketing analytics) isn't something the customer agreed to, even though thescopeis technically the same. Surfaced back onGET /v2/consent/statusso 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 (400otherwise) — 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:
- Consent is granted with an
expires_atand aconsent_token. - The device reports pings (
POST /v2/location/ping) carrying that token — at whatever cadencePOST /v2/monitoring/schedulesets (2h/6h/daily/weekly). - A missed cadence (device off, no GPS) is reported as a heartbeat
(
source: "none",lat/lngof0) rather than silence — this is how "going dark" gets flagged distinctly from "hasn't moved." - The session ends at
expires_at, onconsent/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/pingdoes not carry a device identifier. It's scoped bycustomer_id+loan_id+consent_tokenonly — AfriHex's monitoring layer doesn't itself correlate pings to a specific physical device.device_idexists as an optional field onPOST /v2/kyc/verifyandPOST /v2/verify/proximityinstead, 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
403naming another account's loan means exactly what it says — resources are tenant-isolated, not just permission-gated.
Error and edge cases
consent/delete-datareturns400. 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. purposeomitted on an old integration. Defaults tounspecifiedrather than rejecting the request — existing integrations built before this field existed keep working, but you should backfill a realpurposeas 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 theunspecifieddefault, once you've migrated off older integration code. - Loan/relationship closure in your system triggers
consent/revokeautomatically — it's not a manual, easy-to-forget step. - A customer-facing "delete my data" request calls
revokethendelete-data, in that order, and you handle the400if revoke hasn't propagated yet. -
GET /v2/banking/audit-logis 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.
Related endpoints / next guide
- 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_revokedevents this flow produces.