API Reference
Liveness Detection
Liveness detection tells a live face from a photograph, a screen, or a mask. It is its own endpoint: nothing else calls it for you, so enrollment and identification will happily accept a printed photo unless you check first.
Passive vs. active liveness
- One image, one call
- Neural anti-spoofing model
- No user interaction needed
- Returns a score you threshold yourself
- Requires user action
- Blink or head-turn prompt
- Frames scored server-side
- Blink, head turn and passive in one call
- Much harder to fool with a photo
Standalone liveness check
Run a liveness check without enrolling a face. Useful for verifying a selfie before proceeding with registration in your own flow.
curl -X POST https://api.livexface.com/api/v1/collections/COLLECTION_ID/liveness \
-H "X-API-Key: YOUR_API_KEY" \
-F "[email protected]"{
"success": true,
"data": {
"isLive": true,
"livenessScore": 0.97,
"faceDetected": true,
"faceCount": 1
}
}Response fields
| Field | Type | Description |
|---|---|---|
| isLive | boolean | Whether the score cleared the service threshold. |
| livenessScore | float | Anti-spoof confidence, 0.0–1.0. Higher means more likely real. |
| faceDetected | boolean | Whether any face was found. false makes the score meaningless. |
| faceCount | integer | Faces found in the image; the score describes the largest one. |
Liveness at enrolment
A collection can require liveness for every face enrolled into it. Switch on Require liveness at enrolment when you create or edit the collection in the console, and each enrolment runs the passive check before anything is stored. A face that does not pass is refused with 422:
{
"success": false,
"error": {
"code": "SPOOF_DETECTED",
"message": "the image did not pass the liveness check this collection requires; capture the face live rather than from a photo or screen"
}
}Nothing is kept from a refused image — no face, no stored photo. The same rule covers the references the service adds on its own after a confident match, so a spoof cannot get in through that route either. And if the liveness check itself is unavailable, the enrolment fails rather than going ahead unchecked.
Leave it off for collections built from existing photographs, such as an import from an HR system or a migration from another provider. Those images are not live captures and would be refused.
Checking liveness yourself
Outside enrolment, /liveness reports a score and rejects nothing on your behalf. A successful call returns 200 whether the face is live or not; read isLive and livenessScore and decide what to do.
Try it live
Upload any face photo to test the liveness detection endpoint against your collection.
/collections/{collection_id}/livenessThe image to check for liveness
Active liveness
A single frame can only tell you how the image looks. Active liveness asks the person to do something and watches a short burst of frames for it. Send between 5 and 50 frames as frame_0, frame_1, and so on:
curl -X POST https://api.livexface.com/api/v1/collections/COLLECTION_ID/active-liveness \
-H "X-API-Key: YOUR_API_KEY" \
-F "[email protected]" -F "[email protected]" -F "[email protected]" \
-F "[email protected]" -F "[email protected]"{
"success": true,
"data": {
"isLive": true,
"overallScore": 0.94,
"challenges": {
"blink": { "passed": true, "available": true, "minEar": 0.11, "maxEar": 0.31, "earRange": 0.2 },
"headTurn": { "passed": false, "available": true, "minYaw": -4.2, "maxYaw": 3.8, "yawRange": 8.0 },
"passiveAntispoof": { "passed": true, "available": true, "avgScore": 0.91, "minScore": 0.87, "method": "minifasnet" }
},
"framesAnalyzed": 12,
"framesWithFace": 12
}
}A blink is the challenge that carries the decision. A head turn on its own is not enough to pass: an attacker holding a printed cutout can swing it far enough to look like one, so the frames have to show an eye actually closing and opening. Each challenge reports passed and available separately, so you can see whether a check failed or simply could not run on the frames you sent.
Capture the frames over a second or two of normal video. Fewer than five is rejected, and frames without a visible face are counted in framesAnalyzed but not framesWithFace.