Identity/KYC Verification in Ghana
Ghana Card Facial Verification
Verify that a person physically present is the genuine holder of a Ghana Card by matching a live selfie against the cardholder's record. This runs a liveness check on the photo and a 1:1 face match, then returns the holder's identity details when the face matches.
Use this when you need to prove "this person is who they claim to be", not just that the card number exists. For a plain document lookup without a photo, use Ghana Card, Voter ID & Passport instead.
Prerequisites
You'll need an API key. See Quickstart or Authentication if you don't have one yet.
Note
Verification endpoints use an API key in the X-API-Key header, not a Bearer token. Verification POST requests also accept an optional Idempotency-Key header.
Prepare the selfie
The endpoint expects a live face photo of the person being verified, not a scan of the card. Encode the image as base64 and send it inline, either as a raw base64 string or a data URI (data:image/jpeg;base64,...).
SELFIE="data:image/jpeg;base64,$(base64 -i ./selfie.jpg)"| Requirement | Detail |
|---|---|
| Content | A single, clear, front-facing live photo of the person's face. |
| Format | JPEG or PNG, base64-encoded (data URI or raw base64). |
| Size | Up to ~7 MB decoded. Smaller, well-lit photos verify faster and more reliably. |
| Faces | Exactly one face in frame. Multiple faces are rejected. |
Make the verification request
Set country to GH and idType to ghana_card, and supply the selfie under images.selfie.
curl -X POST https://api.lira.com/api/v1/verify/identity/facial \
-H "X-API-Key: YOUR_API_KEY" \
-H "Idempotency-Key: YOUR_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{
"country": "GH",
"idType": "ghana_card",
"idNumber": "GHA-123456789-0",
"images": {
"selfie": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/..."
}
}'Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
country | string | Yes | Always GH. Facial verification is currently supported for Ghana only. |
idType | string | Yes | Always ghana_card. |
idNumber | string | Yes | The Ghana Card number, 6–20 alphanumeric characters and dashes (e.g. GHA-123456789-0). |
images.selfie | string | Yes | Base64-encoded live face photo (data URI or raw base64). |
mode | string | No | sync (default). Facial verification is synchronous only. |
validation | object | No | Optional fields to cross-check against the matched record. See below. |
Info
Sandbox: Use a sandbox API key to exercise the flow without incurring charges. See Environments.
Optional validation (cross-check)
You can include a validation object to check whether specific caller-provided fields match the matched cardholder record. The response includes a validation object with per-field results, and the verification status becomes inconclusive if any submitted field does not match, even when the face matched.
curl -X POST https://api.lira.com/api/v1/verify/identity/facial \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"country": "GH",
"idType": "ghana_card",
"idNumber": "GHA-123456789-0",
"images": { "selfie": "data:image/jpeg;base64,/9j/4AAQ..." },
"validation": {
"firstName": "Daniel",
"lastName": "Mensah",
"dateOfBirth": "1990-01-15"
}
}'| Validation field | Type | Match rule |
|---|---|---|
firstName | string | Case-insensitive, trimmed. |
lastName | string | Case-insensitive, trimmed. |
dateOfBirth | string | Exact match. Format YYYY-MM-DD. |
Note
The selfie is never stored and never logged. It is used only for the live match and then discarded. Cross-check fields are never persisted either; only the boolean match result is stored.
Read the result
Successful verification (face matched)
{
"id": "c3d4e5f6-...-...-...-...",
"status": "success",
"verificationType": "GHANA_CARD_FACIAL",
"idType": "ghana_card",
"country": "GH",
"identifier": "GHA-123456789-0",
"verifiedAt": "2026-06-05T10:00:00.000Z",
"origin": "api",
"verified": true,
"facialMatch": true,
"firstName": "Daniel",
"lastName": "Mensah",
"dateOfBirth": "1990-01-15",
"gender": "MALE",
"placeOfBirth": "Greater Accra",
"validation": null
}Inconclusive verification (cross-check mismatch)
The face matched, but a submitted validation field did not match the record.
{
"id": "c3d4e5f6-...-...-...-...",
"status": "inconclusive",
"verificationType": "GHANA_CARD_FACIAL",
"idType": "ghana_card",
"country": "GH",
"identifier": "GHA-123456789-0",
"verifiedAt": "2026-06-05T10:00:00.000Z",
"origin": "api",
"verified": false,
"facialMatch": true,
"firstName": "Daniel",
"lastName": "Mensah",
"dateOfBirth": "1990-01-15",
"gender": "MALE",
"placeOfBirth": "Greater Accra",
"validation": {
"firstName": { "value": "Danielle", "match": false },
"lastName": { "value": "Mensah", "match": true },
"dateOfBirth": { "value": "1990-01-15", "match": true }
}
}Failed verification (no match or unusable photo)
{
"id": "c3d4e5f6-...-...-...-...",
"status": "failed",
"verificationType": "GHANA_CARD_FACIAL",
"idType": "ghana_card",
"country": "GH",
"identifier": "GHA-123456789-0",
"verifiedAt": "2026-06-05T10:00:00.000Z",
"origin": "api",
"facialMatch": false,
"error": {
"code": "FACE_MATCH_FAILED",
"message": "Facial verification did not match"
}
}Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique verification ID. |
status | string | success, inconclusive, failed, or error. |
verificationType | string | Always GHANA_CARD_FACIAL. |
idType | string | The idType you submitted (ghana_card). |
country | string | Always GH. |
identifier | string | The Ghana Card number you submitted. |
verifiedAt | string | ISO 8601 timestamp. |
origin | string | api (API-key requests) or dashboard (logged-in dashboard requests). |
verified | boolean | true only when status is success. |
facialMatch | boolean | true when the selfie matched the cardholder (liveness + face match passed); false on a failed check. |
firstName | string | First name as recorded by the registry. May be null. |
lastName | string | Last name as recorded by the registry. May be null. |
dateOfBirth | string | Date of birth, YYYY-MM-DD. May be null. |
gender | string | Gender as recorded by the registry. May be null. |
placeOfBirth | string | Region/place of birth as recorded by the registry. May be null. |
validation | object | Present only when validation was included in the request. Contains per-field match results. |
error | object | Present when status is failed or error. |
error.code | string | Machine-readable failure code. See error handling table below. |
error.message | string | Human-readable description. |
Error handling
Facial failures return a stable error.code your client can branch on. Several are retake-able: show the user the message and let them capture a new photo.
error.code | Cause | Action |
|---|---|---|
FACE_MATCH_FAILED | The face did not match the cardholder record | Genuine non-match; do not retry blindly; route to your fraud/manual review flow |
FACIAL_LIVENESS_FAILED | Liveness check failed (e.g. a photo of a photo) | Ask the user to retake a live selfie |
FACE_NOT_DETECTED | No face found in the image | Ask the user to retake with their face clearly in frame |
FACE_QUALITY_LOW | Face too small, too close, partially covered, or image too low-resolution | Ask the user to retake in good lighting, framing their whole face |
MULTIPLE_FACES_DETECTED | More than one face in the image | Ask the user to retake with only their face in frame |
IDENTIFIER_NOT_FOUND | Ghana Card number not found | Ask the user to check the card number |
FACIAL_VERIFICATION_FAILED | The check could not be completed | Ask the user to retake; retry once before failing the flow |
PROVIDER_RATE_LIMITED | Too many requests in a short window | Back off and retry |
PROVIDER_UNAVAILABLE | Verification temporarily unavailable | Retry with exponential backoff |
A malformed request (missing images.selfie, a bad card number, or unsupported country/idType) returns HTTP 422 with a validation error before any verification runs.
For the full error code reference, see Errors.
Warning
Do not surface raw error.code values directly to end users. Map them to friendly, actionable messages (e.g. FACE_QUALITY_LOW → "We couldn't read your photo clearly. Please retake it in good lighting.").