You send two images: the selfie and the front of the document. You get a 0–100 score and the decision already made against your threshold. It accepts the INE, the passport and any official document worldwide.
Technical questions? Talk to an engineer on WhatsApp — 0% bots.
It's a 1:1 verification: it compares two images against each other. It doesn't search for a face inside a database or build a biometric record of your users.
1Takes the two imagesThe selfie in face and the document front in front, both Base64 (JPG or PNG). The body accepts up to 28 MB.2Detects and isolates the facesIt locates the face in the selfie and extracts the photo from the document. If either is missing, or there's more than one person in the selfie, it tells you instead of guessing.3Compares and decidesIt computes similarity from 0 to 100 and checks it against your threshold. The response already carries the resolved decision in isMatch: your code compares nothing.Two required fields and two optional ones. The names travel in English in the JSON; here's what each one is.
| Field | What it is | Required |
|---|---|---|
face | Your user's selfie, in Base64 (JPG or PNG). It must contain exactly one face: if there are more, the response is MULTIPLE_FACES_DETECTED. | Yes |
front | The front of the document, in Base64. That's where the photo to compare comes from. It accepts any official document worldwide: INE, passport, residence card, professional ID. | Yes |
threshold | Acceptance threshold, 1 to 100. Defaults to 90 (KYC-grade). Overridable per call: a high threshold for sensitive operations, more permissive for low-risk actions. | Optional |
documentType | Requires an exact document type: INE, IFE, MEX_PASSPORT, MEX_RESIDENCE_CARD, MEX_PROFESSIONAL_ID. With ANY it just has to be some recognized document. Omit it and the type isn't validated. | Optional |
The images aren't stored: they're used to compute the comparison and discarded on response. We don't keep biometric templates.
Beyond the result, the response carries a selfie analysis built so you can ask for a useful retry —"take off your sunglasses"— instead of a blind "try again".
faceMatchScoreSimilarity from 0 to 100 between both faces. It arrives as null when the score wasn't the basis of the result —no document detected, no face, multiple faces—: no signal is leaked that doesn't apply.isMatchThe decision, already resolved: true if the score met your threshold. It's the only field your approval logic needs to read.thresholdAppliedThe threshold used on that call. It stays in the response so you can audit later why an operation was approved or rejected.detectedDocumentTypeWhich document was recognized in the front image: INE, MEX_PASSPORT, OTHER…selfieAnalysisWhat was seen in the selfie: quality, face orientation, eyes, glasses, covered face. See the field-by-field detail ↓issues[]Actionable retry hints: wearing_sunglasses, eyes_closed, face_covered, poor_image_quality, not_facing_camera, low_detection_confidence. With those you tell the user exactly what to fix.Most providers in Mexico hand you a score and a yes or no. We also return selfieAnalysis: the facial attributes we detected, ready for your own rules. If your policy requires the face front-on, no sunglasses and eyes open, you don't need another provider or your own vision model — it's already in the same response, at no extra cost.
"selfieAnalysis": { "imageQuality": "excellent", "detectionConfidence": "high", "orientation": "front", "eyesOpen": true, "mouthOpen": false, "wearingGlasses": true, "wearingSunglasses": false, "faceCovered": false, "issues": ["wearing_glasses"] }
A real response: the person is wearing prescription glasses. The comparison passed (isMatch: true) and the detail stays in issues in case your policy treats it differently.
| Field | Values | What it's for |
|---|---|---|
imageQuality | excellent · good · poor | Sharpness and conditions of the photo. On poor, ask for another one before deciding anything. |
detectionConfidence | high · medium · low | How confident the face detection was. Useful to require manual review when it isn't high. |
orientation | front · looking_left · looking_right · looking_up · looking_down · tilted · sideways | Where the person is looking. If your policy requires a front-facing photo, accept only front. |
eyesOpen | true · false | Eyes open. A blink ruins the file photo even if the comparison passes. |
mouthOpen | true · false | Mouth open. Relevant if you need an ID-style photo with a neutral expression. |
wearingGlasses | true · false | Prescription glasses. Many flows allow them; others require removing them for the file. |
wearingSunglasses | true · false | Sunglasses. Almost no policy accepts them: it's the flag most used to force a retry. |
faceCovered | true · false | Face partially covered —mask, scarf, hand—. Ask to remove whatever blocks it. |
issues[] | wearing_glasses · wearing_sunglasses · face_covered · eyes_closed · poor_image_quality · not_facing_camera · low_detection_confidence | The actionable summary. Instead of reading flag by flag, you loop this array and tell the user exactly what to fix. |
orientation: "front", no sunglasses and eyes open, even if the face match passed. You set the policy, not the provider.Be clear on what it is: these attributes describe the image, they don't prove a live person is in front of the camera. They're quality and policy control, not liveness detection.
The type field is your decision point. Three paths: proceed if the faces match, review if the problem is image quality and it's worth asking for another, reject if the result is that it isn't the same person.
| type | What it means | Decision |
|---|---|---|
SUCCESS | The faces match: the score met the threshold. It's the person on the document. | Proceed |
NO_FACE_DETECTED | No face detected in the selfie or in the document. Almost always a blurry, dark or badly framed photo: ask for just that image again. | Review |
MULTIPLE_FACES_DETECTED | More than one face in the selfie. Ask for a new one, with nobody else in frame. | Review |
NO_DOCUMENT_DETECTED | The front image isn't a recognized identity document. It only shows up if you asked for type validation. | Review |
DOCUMENT_MISMATCH | It's a valid document, but not the one you required: you asked for MEX_PASSPORT and an INE arrived. | Review |
FACE_MISMATCH | Both faces were detected fine, but they aren't the same person: the score came in below the threshold. | Reject |
Technical errors arrive separately, with status: "ERROR": an image that isn't JPG/PNG or a body over 28 MB is INVALID_REQUEST with billable: false — no charge.
Same envelope as every OrigoID service: status, type, data. You learn the contract once and it works for biometrics, INE, CURP, RFC and IMSS.
const res = await fetch("https://api.origoid.com/global/biometrics/v1/face-matches", { method: "POST", headers: { "x-api-key": process.env.ORIGOID_API_KEY, "content-type": "application/json", }, body: JSON.stringify({ face: selfieBase64, front: documentFrontBase64, threshold: 90, documentType: "INE", }), }); const { data } = await res.json(); if (data.isMatch) approve();
import os, requests res = requests.post( "https://api.origoid.com/global/biometrics/v1/face-matches", headers={ "x-api-key": os.environ["ORIGOID_API_KEY"], "content-type": "application/json", }, json={ "face": selfie_base64, "front": document_front_base64, "threshold": 90, "documentType": "INE", }, timeout=30, ) result = res.json()
curl -X POST https://api.origoid.com/global/biometrics/v1/face-matches \ -H "x-api-key: $ORIGOID_API_KEY" \ -H "content-type: application/json" \ -d '{"face": "<base64>", "front": "<base64>", "threshold": 90, "documentType": "INE"}'
{
"status": "OK",
"type": "SUCCESS",
"data": {
"faceMatchScore": 96.4,
"isMatch": true,
"thresholdApplied": 90,
"detectedDocumentType": "INE",
"selfieAnalysis": {
"imageQuality": "excellent", "eyesOpen": true,
"wearingSunglasses": false, "issues": []
}
},
"billable": true
}
We'd rather say it before you integrate. Face match answers one very specific question; these others need another piece.
selfieAnalysis measures image quality, not that a live person is in front of the camera. A photo of a photo can pass the comparison.Face match confirms it's the same person; the Lista Nominal confirms the credential is registered and current. Crossing both responses is an if in your backend.
You send two Base64 images: the selfie in face and the document front in front. The API detects the face in each, extracts the document photo and returns a 0–100 score along with isMatch, the decision against your threshold. It's 1:1: it compares two images, it doesn't search a database.
Any official document worldwide with a photo. If you want to require a specific one, use documentType: INE, IFE, MEX_PASSPORT, MEX_RESIDENCE_CARD or MEX_PROFESSIONAL_ID. With ANY it just has to be a recognized document; if it isn't, it answers NO_DOCUMENT_DETECTED.
The default is 90, calibrated for KYC. Lowering it accepts more legitimate cases with difficult photos, but lets more impostors through; raising it cuts fraud at the cost of rejecting legitimate people. Since it's per call, it's common to use a high one for sensitive operations and a more permissive one for low-risk actions. The response includes thresholdApplied so you can audit the decision.
Yes, and it comes in the same response at no extra cost. The selfieAnalysis block carries wearingGlasses, wearingSunglasses, faceCovered, eyesOpen, mouthOpen, the face orientation (front, looking_left, tilted…), the image quality and the detection confidence. With that you apply your own acceptance rules —say, require a front-facing photo with no sunglasses— even if the face match already passed. See the detail.
No. It confirms two faces belong to the same person, and selfieAnalysis describes image quality, but it doesn't verify a live person is in front of the camera: a photo of a photo can pass. It also doesn't certify that the physical document is authentic.
No. The selfie and the document are used to compute the comparison and discarded on response: no image database and no stored biometric templates. Zero retention across all our regions.
One comparison = 1 credit. You start free with courtesy credits, no card, and the price per verification drops with your volume. All plans published. A malformed request isn't charged (billable: false).
Courtesy credits to try face match in production. Access is enabled after a brief validation of your company.