Skip to content

Verifications

Every check creates a verification object with a permanent reference_id. Retrieve it, list it, and resolve pending results.

View as Markdown

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_idstring

    Permanent identifier, spm_ followed by 24 hex characters.

  • objectstring

    Always verification.

  • productstring

    Product id: nin, bvn, face, phone, business, account, signals, passport, drivers_license or voters_card.

  • methodstring

    Method that ran, e.g. nin_raw, nin_inperson, nin_sharecode, bvn_boolean, bvn_core, cac_rc, account_name_enquiry.

  • statusstring

    pending, verified, not_found or failed. A failed single request returns an error response instead; failed appears only in lists and bulk results.

  • matchboolean | null

    true when the record exists and every field you supplied matches. null when nothing was compared (e.g. fraud signals) or the check is pending.

  • field_matchesobject | null

    One boolean per field in your match object, e.g. { "last_name": true }.

  • field_confidenceobject | null

    How close each supplied value is to the record, 0 to 100, e.g. { "first_name": 92 }. Names allow nicknames, spellings and order (Seun ~ Oluwaseun). null for BVN boolean, where NIBSS only answers yes or no.

  • modestring

    sandbox or live, from the key that made the request.

  • reasonstring | null

    The purpose code you declared.

  • subjectstring | null

    Masked identifier, e.g. *******2109. Never the full value.

  • summaryobject | null

    PII-free result for the product: masked names, scores, flags. Documented on each product page.

  • consentobject

    mechanism, consent_id and timestamp: how consent was satisfied.

  • sourcestring

    api, dashboard, mcp or bulk.

  • errorobject | null

    code and message when status is failed.

  • billingobject

    amount_kobo and currency (NGN). Non-zero only for completed live checks.

  • latency_msinteger | null

    Provider round trip in milliseconds.

  • created_atstring

    ISO 8601 timestamp. Also the pagination cursor.

  • updated_atstring

    ISO 8601 timestamp of the last change.

  • providerstring

    Full tier, REST only. Upstream that answered.

  • provider_referencestring | null

    Full tier, REST only. Upstream reference for disputes.

  • dataobject

    Full 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.

GET/v1/verifications/{reference_id}
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:

202 Accepted
{
  "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:

  1. Wait for the webhook. verification.completed fires when the result arrives. See Webhooks.
  2. 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 is 200 once it resolves or 202 while 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.

GET/v1/verifications

Query parameters

  • limitinteger

    Between 1 and 100. Defaults to 20.

  • productstring

    Only this product, e.g. nin.

  • statusstring

    Only this status: pending, verified, not_found or failed.

  • beforestring

    Cursor: the created_at of the last item you received. See Pagination.

curl "http://localhost:4000/v1/verifications?limit=20&product=nin" \
  -H "Authorization: Bearer sk_test_..."
200 OK
{
  "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:

Partial match
{
  "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.