Response shaping
Speedmap receives the full record and decides what leaves the platform. The same check returns different payloads depending on channel and tier.
Upstream registries return whole identity records: names, date of birth, address, phone, photo. Most integrations need far less, usually "does this person exist, and do the details match?". Speedmap keeps the full record encrypted at rest and shapes each response to the channel that asked.
That is data minimisation under the NDPA, and it is what makes the MCP server defensible to a bank's security review.
What each channel receives
| Channel | Returns | data |
|---|---|---|
| REST API, full tier | Assertion plus provider, provider_reference and data, the normalized record | Yes |
| REST API, assertion tier | status, match, field_matches, masked summary and subject, reference_id | No |
| MCP server | Assertion fields only, plus a dashboard link. No PII | No |
| Webhooks | The assertion | No |
Lists (GET /v1/verifications) | The assertion | No |
| Bulk jobs | A job handle. Rows are masked assertions read from the job, never inline | No |
| Dashboard | Assertion; authorized roles can reveal the full record, and every reveal is audited | On reveal |
Speedmap sets your workspace's tier based on your licence and use case; you can see it in the dashboard. The tier applies to both sandbox and live keys, so you can build against the shape you will get in production.
Assertion
{
"reference_id": "spm_8171f3a87cbe221341f7185f",
"object": "verification",
"product": "nin",
"method": "nin_raw",
"status": "verified",
"match": true,
"field_matches": {
"last_name": true
},
"field_confidence": {
"last_name": 100
},
"mode": "sandbox",
"reason": "financialProducts",
"subject": "*******2109",
"summary": {
"first_name": "A*****",
"last_name": "O*****"
},
"consent": {
"mechanism": "client_attested",
"consent_id": null,
"timestamp": "2026-10-19T09:41:07.512Z"
},
"source": "api",
"error": null,
"billing": {
"amount_kobo": 0,
"currency": "NGN"
},
"latency_ms": 412,
"created_at": "2026-10-19T09:41:07.512Z",
"updated_at": "2026-10-19T09:41:07.874Z"
}{
"reference_id": "spm_8171f3a87cbe221341f7185f",
"object": "verification",
"product": "nin",
"method": "nin_raw",
"status": "verified",
"match": true,
"field_matches": {
"last_name": true
},
"field_confidence": {
"last_name": 100
},
"mode": "sandbox",
"reason": "financialProducts",
"subject": "*******2109",
"summary": {
"first_name": "A*****",
"last_name": "O*****"
},
"consent": {
"mechanism": "client_attested",
"consent_id": null,
"timestamp": "2026-10-19T09:41:07.512Z"
},
"source": "api",
"error": null,
"billing": {
"amount_kobo": 0,
"currency": "NGN"
},
"latency_ms": 412,
"created_at": "2026-10-19T09:41:07.512Z",
"updated_at": "2026-10-19T09:41:07.874Z",
"provider": "sandbox",
"provider_reference": "SBX6CB753DB2C",
"data": {
"first_name": "CLARKE",
"middle_name": "ELIZA",
"last_name": "GRIFFIN",
"date_of_birth": "1992-04-18",
"gender": "female",
"phone": "08031234567",
"address": {
"residential": "14 ADEOLA ODEKU STREET",
"town": "VICTORIA ISLAND",
"state": "Lagos",
"lga": "Eti-Osa"
},
"origin": {
"state": "Enugu",
"lga": "Nsukka",
"town": "NSUKKA"
},
"photo": "/9j/4AAQSkZJRgABAQEASABIAAD…"
}
}Masking rules
subjectshows only the last four characters of the identifier:*******2109.- Names in
summarykeep only their first letter:A*****. Account names are masked word by word. - NINs and BVNs are masked in Speedmap's own logs and dashboards too. Identifiers are indexed by keyed hash, and records are encrypted at rest.
Designing for the assertion
Build your decision logic on status, match and field_matches. They are identical across every channel and tier, so the same code works whether a check came from your backend, a bulk job, a webhook or an AI assistant. Treat data as an optional enrichment for full-tier REST calls only.
Questions? Email developers@speedmap.ng. This page is also available as Markdown.