Skip to main content

The first-level fields

Result keys are strings

Every result block is indexed by image number as JSON text: "0", "1"… The biometric matrix is body.biometric["0"]["1"], not [0][1]. In typed languages, deserialize as Map<String, …>.
The diagonal ("0" vs "0") is always 100: it is each face against itself. If you also sent faceVectors, the vectors continue the numbering after the images: 1 image + 1 vector ⇒ keys "0" (the image) and "1" (the vector). Reference values measured with vu_v4 on the team’s test photos: same person ≈ 93–95 · different people ≈ 19. With the same two photos, cosine yields 78 and euclidean_l2 yields 66: never compare scores across methodologies.

inferenceConfidence changes shape

It appears for every image, always, but in two shapes: Type code and confidence as optional. The mapping is fixed: 200 = high, 202 = medium, 406 = low.
Do not confuse levels. The code: 406 nested inside inferenceConfidence does not change the HTTP code or the first-level code, which stay 200. A low-quality image is not an API error: it is a signal to ask the user for another capture.
What degrades the verdict: face mask, closed eyes, blur, non-frontal pose, extreme makeup, and — automatically — any image under 360 px on a side.

The 16 faceFeatures attributes

Each attribute is a 0–100 score where higher = more present: blurry, eyeglasses, sunglasses, faceMask, leftEyeClosed, rightEyeClosed, mouthOpen, beard, mustache, smiling, heavyMakeup, hat, earrings, necklace, necktie, lipstick. Use them to guide the user (“please remove your sunglasses”), not as identity conditions. headPoseEstimation carries the pose in degrees: leftRight (yaw) and upDown (pitch). Zero is perfectly frontal; a face useful for biometrics usually sits within ±15°.

The antispoofing comes nested, with its own scale

antiSpoofingFace["0"] contains the full response of the Facial Antispoofing service, nested as-is:
Decide on its spoofing field (boolean). Do not decide on its inner code or confidence: they carry the antispoofing service’s semantics, not Face Analysis’s.
If the antispoofing service does not respond, antiSpoofingFace["0"] arrives as null and the rest of the response is still 200. Treat null as “no verdict” — never as an approval.

Deserializer particularities

  1. Result blocks are indexed by string ("0", "1"), not by integer.
  2. inferenceConfidence has two shapes: code and confidence are optional.
  3. antiSpoofingFace[i] can be an object or null.
  4. confidences duplicates biometric: ignore it, but do not fail when it appears.
  5. With faceVectors, result numbering includes the vectors after the images.
  6. The 500s arrive with a plain-text body, not JSON — see Errors.

Next: Errors

Error codes, the plain-text 500s, the batch abort with imageNumber, and what to retry.
Last modified on September 9, 2026