Verifications
Every check creates a verification object with a permanent reference_id. Retrieve it, list it, and resolve pending results.
Each call to a product endpoint creates a verification. Speedmap writes it to the database before it calls the provider, so even a timed-out check has a reference_id you can use to recover the result.
The verification object
reference_idstringPermanent identifier,
spm_followed by 24 hex characters.objectstringAlways
verification.productstringProduct id:
nin,bvn,face,phone,business,account,signals,passport,drivers_licenseorvoters_card.methodstringMethod that ran, e.g.
nin_raw,nin_inperson,nin_sharecode,bvn_boolean,bvn_core,cac_rc,account_name_enquiry.statusstringpending,verified,not_foundorfailed. A failed single request returns an error response instead;failedappears only in lists and bulk results.matchboolean | nulltruewhen the record exists and every field you supplied matches.nullwhen nothing was compared (e.g. fraud signals) or the check is pending.field_matchesobject | nullOne boolean per field in your
matchobject, e.g.{ "last_name": true }.field_confidenceobject | nullHow close each supplied value is to the record, 0 to 100, e.g.
{ "first_name": 92 }. Names allow nicknames, spellings and order (Seun ~ Oluwaseun).nullfor BVNboolean, where NIBSS only answers yes or no.modestringsandboxorlive, from the key that made the request.reasonstring | nullThe purpose code you declared.
subjectstring | nullMasked identifier, e.g.
*******2109. Never the full value.summaryobject | nullPII-free result for the product: masked names, scores, flags. Documented on each product page.
consentobjectmechanism,consent_idandtimestamp: how consent was satisfied.sourcestringapi,dashboard,mcporbulk.errorobject | nullcodeandmessagewhenstatusisfailed.billingobjectamount_koboandcurrency(NGN). Non-zero only for completed live checks.latency_msinteger | nullProvider round trip in milliseconds.
created_atstringISO 8601 timestamp. Also the pagination cursor.
updated_atstringISO 8601 timestamp of the last change.
providerstringFull tier, REST only. Upstream that answered.
provider_referencestring | nullFull tier, REST only. Upstream reference for disputes.
dataobjectFull tier, REST only. The normalized record. See Response shaping.
Retrieve a verification
Fetch any earlier check by its reference_id. The response has the same shape and tier as the original call.
curl "http://localhost:4000/v1/verifications/spm_8171f3a87cbe221341f7185f" \
-H "Authorization: Bearer sk_test_..."An unknown reference, or one that belongs to the other mode, returns 404 not_found.
Pending verifications
Government registries sometimes answer slowly. When the provider does not answer within the request window, Speedmap returns 202 Accepted with status: "pending" instead of failing:
{
"reference_id": "spm_8171f3a87cbe221341f7185f",
"object": "verification",
"product": "nin",
"method": "nin_raw",
"status": "pending",
"match": null,
"field_matches": null,
"field_confidence": {
"last_name": 100
},
"mode": "sandbox",
"reason": "financialProducts",
"subject": "*******9999",
"summary": null,
"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": 10012,
"created_at": "2026-10-19T09:41:07.512Z",
"updated_at": "2026-10-19T09:41:07.874Z"
}You are not charged for a pending check until it completes. To resolve it, either:
- Wait for the webhook.
verification.completedfires when the result arrives. See Webhooks. - Requery. Call
GET /v1/verifications/{reference_id}. For products whose provider supports requery (NIN today), a pending check is re-queried with the provider on read, and the response is200once it resolves or202while it is still pending.
Poll with back-off (for example after 2, 5, 15 and 30 seconds) rather than in a tight loop. In the sandbox, any NIN of all nines (99999999999) returns 202 and resolves on the first requery.
List verifications
Returns the assertion view of your verifications, newest first, for the mode of your key. Lists never contain data, whatever your tier.
Query parameters
limitintegerBetween 1 and 100. Defaults to
20.productstringOnly this product, e.g.
nin.statusstringOnly this status:
pending,verified,not_foundorfailed.beforestringCursor: the
created_atof the last item you received. See Pagination.
curl "http://localhost:4000/v1/verifications?limit=20&product=nin" \
-H "Authorization: Bearer sk_test_..."{
"object": "list",
"data": [
{
"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_5b0e2c9d1f7a3e6b8c4d2a10",
"object": "verification",
"product": "account",
"method": "account_name_enquiry",
"status": "verified",
"match": true,
"field_matches": null,
"field_confidence": null,
"mode": "sandbox",
"reason": null,
"subject": "******6789",
"summary": {
"account_name_masked": "A***** C***** O*****",
"bank_name": "Guaranty Trust Bank",
"name_match": true
},
"consent": {
"mechanism": "not_required",
"consent_id": null,
"timestamp": "2026-10-19T09:41:07.512Z"
},
"source": "api",
"error": null,
"billing": {
"amount_kobo": 0,
"currency": "NGN"
},
"latency_ms": 190,
"created_at": "2026-10-19T09:41:07.512Z",
"updated_at": "2026-10-19T09:41:07.874Z"
}
],
"has_more": true
}Matching
When you send a match object, each field is compared with the record after trimming and case-folding (date_of_birth must match exactly, as YYYY-MM-DD). Each field gets a yes/no in field_matches and, when Speedmap holds the record, a 0 to 100 score in field_confidence, so a misspelt or shortened name (Clark for Clarke, Seun for Oluwaseun) shows up as a near miss rather than a flat no:
{
"status": "verified",
"match": false,
"field_matches": {
"first_name": false,
"last_name": true,
"date_of_birth": true
},
"field_confidence": {
"first_name": 94,
"last_name": 100,
"date_of_birth": 100
},
"summary": {
"first_name": "A*****",
"last_name": "O*****"
}
}status: "verified" with match: false means the identity exists but does not belong to the details you hold. Treat it as a failed check, not as a not-found.
Questions? Email developers@speedmap.ng. This page is also available as Markdown.