Skip to content

Face Liveness & Match

Passive liveness detection and face comparison against the BVN photo in one call, via NIBSS N-Face.

View as Markdown

Runs passive liveness detection on a selfie and, when you pass a BVN, compares the face with the photo on the BVN record, through NIBSS N-Face. One call, two scores.

POST/v1/verify/face
Availability
Sandbox and live
Indicative price
₦150.00 per completed check
Consent
The live selfie is the consent (in_person_selfie).
MCP tool
face_match (image by https URL)

Request

Body parameters

  • imagestringrequired

    Selfie as base64 JPEG/PNG, or an https URL when image_type is url. At least 20 characters.

  • image_typestring

    One of: base64, url. Defaults to base64.

  • bvnstring

    Compare the selfie against the photo on this BVN. Omit for liveness only. Format: 11 digits.

  • liveness_thresholdnumber

    Between 0 and 1. Defaults to 0.6.

  • face_match_thresholdnumber

    Between 0 and 1. Defaults to 0.9.

  • orderstring

    Liveness first, comparison first, or both in parallel. One of: pl_fc_serial, fc_pl_serial, fc_pl_parallel. Defaults to pl_fc_serial.

  • os_typestring

    One of: ios, android, desktop, unknown. Defaults to unknown.

  • reasonstringrequired

    Purpose of the check. One of the 38 NIMC purpose codes. See the purpose code list.

  • Omit bvn for liveness only (method face_liveness); include it for liveness and match (face_liveness_match).
  • With image_type: "url", image must be a public https URL.
  • match is true when liveness passes and, if a BVN was supplied, the face comparison passes too.
  • To capture the selfie with an active liveness check inside your iOS, Android, React Native or Flutter app, see Mobile apps.

Send an Idempotency-Key header so a retried request is never billed twice. See Idempotency.

curl -X POST http://localhost:4000/v1/verify/face \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "image": "<base64 selfie>",
  "bvn": "22222222221",
  "reason": "financialProducts"
}'

Response

A completed check returns 200 with a verification object. status is verified or not_found. If the provider has not answered in time you get 202 with status: "pending"; retrieve it later or wait for the verification.completed webhook.

200 OK · assertion
{
  "reference_id": "spm_8171f3a87cbe221341f7185f",
  "object": "verification",
  "product": "face",
  "method": "face_liveness_match",
  "status": "verified",
  "match": true,
  "field_matches": null,
  "field_confidence": null,
  "mode": "sandbox",
  "reason": "financialProducts",
  "subject": "*******2221",
  "summary": {
    "liveness_passed": true,
    "liveness_confidence": 0.885,
    "liveness_quality": 0.885,
    "face_match_passed": true,
    "face_match_confidence": 0.988,
    "face_match_quality": 0.902,
    "session_code": "11b004ce-9f2f-43df-858e-79eacf50af07",
    "thresholds": {
      "liveness": 0.6,
      "face_match": 0.9
    }
  },
  "consent": {
    "mechanism": "in_person_selfie",
    "consent_id": null,
    "timestamp": "2026-10-19T09:41:07.512Z"
  },
  "source": "api",
  "error": null,
  "billing": {
    "amount_kobo": 0,
    "currency": "NGN"
  },
  "latency_ms": 1180,
  "created_at": "2026-10-19T09:41:07.512Z",
  "updated_at": "2026-10-19T09:41:07.874Z"
}

summary

  • liveness_passedboolean

    Liveness confidence reached liveness_threshold.

  • liveness_confidencenumber

    Liveness confidence, 0 to 1.

  • liveness_qualitynumber

    Image quality score for liveness, 0 to 1.

  • face_match_passedboolean | null

    Face comparison reached face_match_threshold. null without a BVN.

  • face_match_confidencenumber | null

    Similarity to the BVN photo, 0 to 1.

  • face_match_qualitynumber | null

    Image quality score for the comparison.

  • session_codestring

    N-Face session identifier, also returned as provider_reference.

  • thresholdsobject

    The liveness and face_match thresholds that were applied.

Full-tier accounts calling the REST API also receive provider, provider_reference and data, the normalized record. MCP, webhooks, lists and bulk results never include it. See Response shaping.

Full tier only
{
  "provider": "sandbox",
  "provider_reference": "SBX6CB753DB2C",
  "data": {
    "liveness_passed": true,
    "liveness_confidence": 0.885,
    "liveness_quality": 0.885,
    "face_match_passed": true,
    "face_match_confidence": 0.988,
    "face_match_quality": 0.902,
    "session_code": "11b004ce-9f2f-43df-858e-79eacf50af07",
    "thresholds": {
      "liveness": 0.6,
      "face_match": 0.9
    }
  }
}

Test values

Send these bodies with a sandbox key. More outcome triggers are on the Sandbox page.

Live and matching
{
  "image": "data-LIVE-selfie-0001",
  "bvn": "22222222221",
  "reason": "financialProducts"
}
Spoof (fails liveness)
{
  "image": "data-SPOOF-photo-of-photo",
  "reason": "financialProducts"
}
Different person
{
  "image": "data-MISMATCH-selfie",
  "bvn": "22222222221",
  "reason": "financialProducts"
}

Errors

StatusCodeMeaning
400
invalid_request
The body failed validation. details lists each field.
401
unauthorized
Missing or invalid API key.
402
insufficient_balance
Live only: wallet balance is below the check price.
403
not_entitled
Your workspace is not enabled for this product or method.
409
idempotency_key_reused
The Idempotency-Key was used with a different body.
422
provider_rejected_request
The upstream registry rejected the request.
503
verification_unavailable
Temporary failure. Retry, with the same or a new Idempotency-Key.

All errors share one shape. See Errors for the full list.

Questions? Email developers@speedmap.ng. This page is also available as Markdown.