Skip to main content

Face verification

The face endpoints compare faces two ways: 1:1, is this selfie the person on this document, and 1:N, is this face already in your tenant's gallery. Every comparison is a cosine similarity between face embeddings computed on the server, judged against a threshold your tenant can tune on the dashboard's Decision thresholds page.

1:1 verification​

POST /v1/face/verify takes two images as image_a and image_b (multipart) and returns:

{
"match": true,
"similarity": 0.71,
"threshold": 0.45,
"image_a": { "face_bbox": { "…": "…" }, "quality": { "…": "…" } },
"image_b": { "face_bbox": { "…": "…" }, "quality": { "…": "…" } },
"model_version": "…",
"request_id": "…"
}

match is similarity >= threshold (face_match_threshold, default 0.45). A document photo can be sent as image_a directly: the main portrait is located on a CID, SRC, passport or work permit, and the small ghost portrait printed on the card is ignored; a second, different person's face in image_a fails with multiple_faces_detected_in_image_a. Run /v1/ocr on the same photo first, which checks the face against the document's portrait frame. Each image must contain exactly one clear face; otherwise the call fails with no_face_detected, multiple_faces_detected or low_quality_face, suffixed with the image (…_in_image_b).

Inside a verification session the match runs on the server between the document portrait and the frame the liveness check scored; the app never uploads a selfie for matching.

Registering a face stores its embedding, not the image unless your storage policy keeps source images, under a customer_ref. Every gallery call is secret key only: make it from your server. A session token or publishable key gets 403 forbidden.

CallPurpose
POST /v1/face/registrations (image, customer_ref)Add a face to the gallery. Returns fr_….
POST /v1/face/registrations/verify (image, customer_ref)1:1 against everything registered for that customer_ref.
POST /v1/face/search (image, optional limit, min_similarity)1:N: the most similar registrations, best first.
POST /v1/face/dedupe (image)The single best match against the whole gallery, with is_duplicate judged against face_dedupe_threshold (default 0.55). Use it before onboarding to catch the same person under two identities.
GET /v1/face/registrations, GET / DELETE /v1/face/registrations/{id}List (cursor-paginated), read and delete registrations.

Embeddings are tied to the model version that produced them. After a model upgrade, a comparison against an older embedding returns 409 model_version_mismatch; re-register that face.

Storage​

Embeddings are kept for face_embedding_ttl_days (default 365) and source images only when store_source_images is on. Registrations appear on the dashboard's Face registrations page.

Webhook​

POST /v1/face/verify publishes face.verify.completed with the result. See Webhooks.