Face Comparison
The Face Comparison API compares two face images and returns whether they belong to the same person, along with a similarity score. Typical use: compare a live selfie against the face cropped from an ID document.
It is a standalone service — it does not require a KYC submission or any customer onboarding state.
Overview
Use this endpoint when you want to confirm that the person presenting an ID is the same person captured in a liveness photo, without going through Azakaw's onboarding UI.
For each request the API will:
- Take two images uploaded by the caller.
- Run face matching via the Azakaw Face Comparison service.
- Return a boolean match decision plus similarity and quality scores.
Data handling
- Both uploaded images are processed in memory and not persisted.
- Only the comparison result (match boolean, scores, status) is persisted as part of an audit log entry.
- Nothing is uploaded to blob storage.
Authentication
All requests to this API require authentication using a bearer token in the Authorization header:
Authorization: Bearer your-token-here
For details on how to obtain an authentication token, please refer to the Authentication documentation. Tokens issued by AppSessionManager carry a services: External claim that this endpoint requires.
Compare Two Faces
POST {base_url}/ExtFaceComparison/Compare
Request
The request must be sent as multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
LivenessFace | File | Yes | Selfie or liveness photo of the person. JPG, PNG, BMP, or TIFF. |
FaceFromDocument | File | Yes | Face cropped from an ID document (passport, ID card, etc.). Same supported formats as LivenessFace. |
Both files must be non-empty. The order does not matter — the comparison is symmetric.
Example
curl --location '{base_url}/ExtFaceComparison/Compare' \
--header 'Authorization: Bearer your-token-here' \
--form 'LivenessFace=@"/path/to/selfie.jpg"' \
--form 'FaceFromDocument=@"/path/to/id-face.jpg"'
Response
{
"version": null,
"statusCode": 200,
"messages": [
"Processed successfully"
],
"result": {
"isFaceMatch": true,
"matchingSimilarity": 0.9998999834060669,
"matchingScore": 95.0,
"status": "FACER_OK"
}
}
Response Fields
The result object:
| Field | Type | Description |
|---|---|---|
isFaceMatch | boolean | true when the comparison passed the provider's match threshold. |
matchingSimilarity | decimal | Raw similarity in [0, 1]. 1.0 means identical embeddings. |
matchingScore | decimal | Provider-specific match score (typically [0, 100]). |
status | string | Service status code. FACER_OK indicates a successful comparison. See Status values below for common values. |
Status values
status is the raw code returned by the Azakaw Face Comparison service. The most common values:
| Code | Meaning |
|---|---|
FACER_OK | Comparison succeeded; isFaceMatch is meaningful. |
FR_IMAGE_EMPTY | One of the inputs was empty. The endpoint normally returns 400 before reaching this state — only seen if a malformed multipart slips through. |
FR_FACE_NOT_DETECTED | No face was detected in one of the inputs. isFaceMatch will be false. Re-capture with the face clearly visible. |
FR_LANDMARKS_NOT_DETECTED | A face was detected but key landmarks were not. Usually a quality issue (blur, partial occlusion). |
FR_IMAGE_DECODE_ERROR | Image format could not be decoded. Verify the file is a JPG / PNG / BMP / TIFF. |
FACER_LOW_QUALITY | Source images were judged too low quality to compare reliably. Re-capture under better lighting. |
A status other than FACER_OK does not always mean failure — always check isFaceMatch together with status.
Rate Limit
This endpoint is rate-limited at 5 requests per second. Excess requests return HTTP 429 Too Many Requests.
Error Handling
| Status | Meaning |
|---|---|
200 | Request processed. Inspect result.status and result.isFaceMatch. |
400 | Validation failure — e.g. LivenessFace or FaceFromDocument missing or empty. |
401 | Missing or invalid Bearer token. |
403 | Token does not carry the required services: External claim. |
413 | Uploaded file exceeds the configured size limit. |
429 | Rate limit exceeded. |
500 | Unexpected server error. |
Error responses follow the standard envelope:
{
"version": null,
"statusCode": 400,
"messages": [
"LivenessFace is empty."
],
"result": null
}
Best Practices
- Capture quality. Both faces should be well-lit, face-front, and unobstructed. Sunglasses, masks, and extreme angles reduce match confidence.
- Liveness first. This endpoint compares two static images — it does not perform liveness detection. Pair it with your liveness capture flow so the
LivenessFaceyou send is a fresh capture, not a still image. - Threshold interpretation.
isFaceMatchreflects the provider's threshold. If you need a stricter / looser policy, consumematchingSimilaritydirectly and apply your own threshold. - Status alongside match. Treat any
statusother thanFACER_OKas a signal to surface a friendly error to the user (typically a re-capture prompt) rather than relying solely onisFaceMatch = false. - Privacy. No images are stored. Only the comparison outcome is persisted for audit.