> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumiid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Government ID Face Match: NIN and BVN Selfie Verification

> Verify a live selfie against a Nigerian NIN or BVN photo. LumiID fetches the government biometric automatically — submit only the selfie and ID number.

The LumiID Government ID Face Match API verifies a live selfie against the official biometric photo associated with a customer's Nigerian NIN or BVN. Unlike a standard face match — where you must supply both images yourself — this API handles the reference image for you. Submit the selfie and the identity number, and LumiID automatically retrieves the trusted government-issued photo from NIMC or NIBSS, performs an AI-powered facial comparison, and returns a match result.

This removes the need for you to store or manage sensitive government identity photos while providing stronger, authoritative identity assurance for KYC, AML, and fraud-prevention workflows.

## Key capabilities

| Capability | Detail |
| - | - |
| **Government Data Integration** | Reference photos retrieved directly from NIMC (NIN) and NIBSS (BVN) |
| **AI-Powered Facial Recognition** | Deep learning facial embeddings determine whether both images belong to the same individual |
| **Built for Compliance** | Satisfies KYC, AML, CDD, and NDPR requirements |
| **Fast Response** | Average response time under 2 seconds |
| **Audit Ready** | Every request returns a unique `request_id` and timestamp |

***

## Endpoint

```text theme={null}
POST /v1/face/id-match/
```

### Headers

| Header | Value |
| - | - |
| `Authorization` | `Bearer YOUR_SECRET_KEY` |
| `Content-Type` | `application/json` |

### Request body

**id\_type** `string` *required*

The type of government identity to look up. Supported values: `nin`, `bvn`.

**id\_number** `string` *required*

The customer's government-issued identity number corresponding to the selected `id_type`.

**selfie** `string` *required*

Base64-encoded selfie image captured live from your user.

**threshold** `float`

Matching threshold between `0.0` and `1.0`. Comparisons that score above this threshold are classified as a match. Defaults to `0.75`. Use the default unless your risk model specifically requires a stricter value.

### Supported identity sources

| Identity | Authority | Status |
| - | - | - |
| National Identity Number (NIN) | NIMC | ✅ Supported |
| Bank Verification Number (BVN) | NIBSS | ✅ Supported |
| Passport | Nigeria Immigration Service | 🔜 Coming Soon |
| Driver's License | FRSC | 🔜 Coming Soon |
| Voter Card | INEC | 🔜 Coming Soon |

***

## Integration flow

**1. Capture a live selfie**

Use a live camera feed in your application to capture a front-facing selfie from your user.

**2. Collect the identity number**

Ask the customer to provide their NIN or BVN. This is the identity number you will pass as `id_number`.

**3. Send both values to the endpoint**

POST the `selfie`, `id_type`, and `id_number` to `/v1/face/id-match/`. Include your optional `threshold` if your risk policy requires it.

**4. LumiID runs the comparison**

LumiID automatically retrieves the official government biometric photograph from NIMC or NIBSS, performs an AI-powered facial comparison, calculates a similarity confidence score, and returns the result.

**5. Approve or escalate**

Use the `match_result` and `confidence.score` in the response to approve the onboarding, request a new selfie, or trigger a manual review based on your internal business rules.

***

## Code examples

```python Python theme={null}
import requests
import base64

with open("selfie.jpg", "rb") as image:
    selfie = base64.b64encode(image.read()).decode()

response = requests.post(
    "https://api.lumiid.com/v1/face/id-match/",
    json={
        "id_type": "nin",
        "id_number": "89184072280",
        "selfie": selfie,
        "threshold": 0.75
    },
    headers={
        "Authorization": "Bearer YOUR_SECRET_KEY",
        "Content-Type": "application/json"
    }
)

print(response.json())
```

```javascript Node.js theme={null}
const axios = require("axios");

const response = await axios.post(
  "https://api.lumiid.com/v1/face/id-match/",
  {
    id_type: "nin",
    id_number: "89184072280",
    selfie: "<BASE64_IMAGE>",
    threshold: 0.75
  },
  {
    headers: {
      Authorization: "Bearer YOUR_SECRET_KEY"
    }
  }
);

console.log(response.data);
```

```bash cURL theme={null}
curl --request POST \
  https://api.lumiid.com/v1/face/id-match/ \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id_type": "nin",
    "id_number": "89184072280",
    "selfie": "BASE64_IMAGE",
    "threshold": 0.75
  }'
```

### Success response

```json theme={null}
{
  "success": true,
  "code": "FACE_MATCH_VERIFIED",
  "message": "Face match completed successfully",
  "summary": {
    "verified": true,
    "verification_type": "FACE_MATCH",
    "provider": "LumiID",
    "confidence_score": 0.9842
  },
  "data": {
    "match_result": "CONFIRMED",
    "confidence": {
      "score": 0.9842,
      "threshold": 0.75,
      "status": "STRONG_MATCH"
    },
    "details": {
      "reason_code": "MATCH_SUCCESS",
      "remarks": "Identity verified successfully"
    }
  },
  "meta": {
    "request_id": "req_634490e898c1",
    "timestamp": "2026-03-10T17:45:12Z"
  }
}
```

### Response fields

**success** `boolean`

Indicates whether the request completed successfully.

**code** `string`

Machine-readable response code.

**message** `string`

Human-readable response message.

**summary** `object`

High-level verification summary.

**summary fields**

**verified** `boolean`

Indicates whether both faces belong to the same individual.

**verification\_type** `string`

Always `FACE_MATCH`.

**provider** `string`

Always `LumiID`.

**confidence\_score** `float`

Overall confidence score between `0` and `1`.

**data** `object`

Detailed face comparison result.

**data fields**

**match\_result** `string`

The verification outcome. Returns `CONFIRMED`, `MISMATCH`, or `INCONCLUSIVE`.

**confidence** `object`

Confidence details for the comparison.

**confidence fields**

**score** `float`

Similarity score for the comparison.

**threshold** `float`

The threshold applied during this comparison.

**status** `string`

Match strength classification (e.g. `STRONG_MATCH`).

**details** `object`

Additional decision context.

**details fields**

**reason\_code** `string`

Internal decision code.

**remarks** `string`

Human-readable explanation of the outcome.

**meta** `object`

Request metadata.

**meta fields**

**request\_id** `string`

Unique request identifier. Store this for audit and support purposes.

**timestamp** `string`

ISO 8601 timestamp of when the request was processed.

***

## Confidence score guide

| Score range | Interpretation |
| - | - |
| 0.95 – 1.00 | Extremely Strong Match |
| 0.90 – 0.94 | Very Strong Match |
| 0.80 – 0.89 | Strong Match |
| 0.75 – 0.79 | Acceptable Match |
| Below 0.75 | Likely Mismatch |

***

## Match results

### `CONFIRMED`

The live selfie matches the official government biometric record. Proceed with onboarding.

### `MISMATCH`

The faces belong to different individuals. Reject the verification or ask the user to submit a new selfie.

### `INCONCLUSIVE`

The system could not confidently compare the faces. Common causes include a blurry selfie, multiple faces in the frame, poor lighting, or a partially obscured face. Request a new capture before making a decision.

***

## Error codes

| HTTP | Code | Cause and resolution |
| - | - | - |
| `400` | `INVALID_REQUEST` | Missing or invalid request fields. Check all required parameters. |
| `400` | `INVALID_ID_TYPE` | Unsupported identity type. Supported values are `nin` and `bvn`. |
| `400` | `INVALID_IMAGE` | The selfie could not be decoded. Verify the Base64 encoding. |
| `401` | `INVALID_API_KEY` | Invalid or missing API key. Check your `Authorization` header. |
| `401` | `SUBSCRIPTION_REQUIRED` | Government ID Face Match is not enabled on your account. Contact LumiID support. |
| `402` | `INSUFFICIENT_FUNDS` | Your wallet balance is insufficient. Top up your account and retry. |
| `404` | `ID_NOT_FOUND` | The government identity record was not found. Verify the `id_number` is correct. |
| `422` | `FACE_NOT_DETECTED` | No face was detected in the uploaded selfie. Ask the user to retake the photo. |
| `422` | `MULTIPLE_FACES_DETECTED` | Only one face is allowed per image. Ensure the selfie shows a single face. |
| `429` | `RATE_LIMIT_EXCEEDED` | Too many requests in a short period. Back off and retry. |
| `500` | `SERVER_ERROR` | Unexpected server error. Retry the request. |
| `503` | `SERVICE_UNAVAILABLE` | The government identity provider is temporarily unavailable. Retry after a short delay. |
| `504` | `TIMEOUT` | Upstream verification timed out. Retry after a short delay. |

***

## Recommended identity verification flow

For the highest level of fraud protection, run these checks in sequence:

**1. Passive Liveness Detection**

Run the [Liveness Detection API](https://docs.lumiid.com/api-reference/liveness-detection) to confirm the selfie was captured from a real, live person — not a photo, replay, or deepfake.

**2. Government Identity Verification**

Validate the customer's NIN or BVN against the official registry to confirm the identity number exists and belongs to a real person.

**3. Government ID Face Match**

Submit the verified selfie and identity number to this endpoint. LumiID compares the live selfie to the official government biometric photo.

**4. Approve or Escalate**

Use the `match_result` and `confidence.score` to complete onboarding or trigger a manual review. This layered approach protects against impersonation, synthetic identity fraud, and presentation attacks while providing a strong audit trail for KYC and AML compliance.

***

## Best practices

* Always run [**Passive Liveness Detection**](https://docs.lumiid.com/api-reference/liveness-detection) before this endpoint.
* Capture selfies in **good, even lighting** without harsh shadows.
* Ensure **only one face** appears in the selfie before submitting.
* Avoid selfies where the user is wearing **sunglasses, a mask, or heavy filters**.
* Use the default threshold of `0.75` unless your risk model requires stricter verification.
* Store the returned `request_id` for every request — you will need it for audit trails and support queries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.