# Validación de QR (V3) Fuente: /identity-verification-v3/qr-validation/ Solo disponible en V3 Las credenciales para votar modelo **G/H** (2019 en adelante) incluyen dos códigos QR en el reverso, firmados digitalmente por el INE, que guardan los mismos datos que el frente de la credencial —CURP, nombre, vigencia— y una fotografía del titular en baja resolución. La validación de QR lee esos códigos, verifica su firma digital y **coteja lo que dicen contra el resto del documento**: el CURP y el nombre extraídos por OCR del anverso, y el rostro capturado durante la video-identificación. Es una comprobación adicional para detectar una credencial alterada: alguien pudo modificar el anverso (foto, nombre, CURP) dejando intacto el reverso original, o viceversa. > **Nota** > > Es una validación **opcional y con costo adicional** — no se ejecuta a menos que la pidas > explícitamente al [crear la sesión](/identity-verification-v3/create-verification-session/). ## Cómo activarla Envía `qr_validation: true` en el cuerpo de la solicitud al crear la sesión: **JSON** ```json { "validations": ["INE", "CURP"], "qr_validation": true } ``` **cURL** ```bash curl -X POST https://api.verificamex.com/identity/v3/identity/sessions \ -H "Authorization: Bearer {TU_TOKEN}" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{ "validations": ["INE", "CURP"], "qr_validation": true }' ``` > **Consejo** > > `validacion_qr` funciona como alias del mismo parámetro, por si ya lo usas así en tu integración. > Ambos aceptan `true`/`false` o `"1"`/`"0"`. > **Tiene un costo adicional** > > La validación de QR consume **5 tokens extra** por sesión cuando la sesión incluye las validaciones > `INE` y `CURP` (el valor por defecto), y **10 tokens extra** si no incluye ambas. Solo se cobra > **si el QR se pudo leer**: si la credencial no trae QR o no se pudo leer, no se cobra. Aun así, > considera que no toda credencial la soporta —lee la siguiente sección antes de habilitarla para > todos tus usuarios. ## No todas las credenciales tienen QR Solo el modelo **G/H** trae los dos códigos QR en el reverso. Las credenciales modelo **DEF** (anteriores a esa generación) no los incluyen — no hay nada que leer. Cuando esto ocurre, el campo `qr_not_applicable` viene en `true` dentro del resultado, y **la sesión no se penaliza por ello**: es una comprobación que no aplica a ese documento, no un fallo. Tampoco se penaliza cuando el QR sí existe pero no se pudo leer bien (foto borrosa, mala iluminación, reflejo): eso no es evidencia de fraude, así que no baja el resultado. Solo cuenta cuando el QR **se leyó con éxito** y sus datos no coinciden con el resto del documento — ver [Cómo afecta el resultado](#cómo-afecta-el-resultado-de-la-sesión). ## Estructura de la respuesta Tanto el [detalle de la sesión](/identity-verification-v3/show-verification-session/) como el [webhook](/identity-verification-v3/webhooks/) incluyen el campo `qr_validation`. Es `null` si la sesión no pidió esta validación. | Campo | Tipo | Descripción | | - | - | - | | attempted | `Boolean` | Siempre `true` cuando la sesión pidió `qr_validation`. | | ok | `Boolean` | `true` si los códigos QR se leyeron y decodificaron correctamente. | | `qr_not_applicable` | `Boolean` | `true` si la credencial es modelo DEF y no trae los 2 QR del reverso. | | stage | `String` | Etapa alcanzada por el proceso de lectura (`"done"` cuando terminó sin problema). | | error | `String` | Motivo de la falla de lectura, o `null` si no hubo. | | modelo | `String` | Formato de cifrado detectado en el QR (`"G/H"`). | | `signature_checked` | `Boolean` | Si se verificó la firma digital del QR. | | `signature_valid` | `Boolean` | Si la firma digital es válida. | | fields | `Object` | Datos decodificados del QR: `curp`, `nombres`, `primer_apellido`, `segundo_apellido`, `cic`, `vigencia`, `sexo`, `numero_emision`, `fecha`, entre otros. | | `data_match` | `Object` | Cotejo del QR contra el OCR del anverso — ver abajo. | | `face_match` | `Object` | Cotejo del rostro embebido en el QR contra el rostro capturado — ver abajo. | **`data_match`** trae una llave por cada dato cotejado (`curp`, `nombre`). Cada una es un objeto `{ qr, ocr, match }` con el valor leído del QR, el valor leído por OCR, y si coinciden. Si no hubo datos suficientes para comparar un campo, esa llave no aparece —no es lo mismo que un `match: false`—. **`face_match`** es `{ compared, confidence, matched, threshold }`. Si el QR no traía fotografía o no se detectó rostro en el anverso, `compared` es `false` y no se hizo la comparación —tampoco es un fallo—. `threshold` es la similitud mínima con la que se calificó: el `qr_face_match_threshold` que enviaste al crear la sesión, u `80` por defecto. Ver [Umbrales de biometría](/identity-verification-v3/biometric-thresholds/). > **Diferencia con la V2** > > Esta validación no existe en la V2: es exclusiva de las sesiones creadas con V3. ## Cómo afecta el resultado de la sesión `qr_validation` solo pesa en el `result` final (y en el arreglo `errors`) cuando el QR **se pudo leer con éxito y sí aplica a esa credencial**. En ese caso, un dato que no coincida es una señal real de fraude —alguien pegó un QR ajeno, válido en sí mismo, sobre una credencial distinta— y pesa igual que un fallo de MRZ o de biometría: el resultado de la sesión pasa a **`0`**. 1. **No se pidió `qr_validation`, no aplica a la credencial, o el QR no se pudo leer** — no afecta el resultado en ningún sentido. 2. **El QR se leyó bien y todo coincide** — no agrega ningún error; el resultado depende del resto de las validaciones como siempre. 3. **El QR se leyó bien pero el CURP, el nombre o el rostro no coinciden** — se agrega una entrada a `errors` y el `result` de la sesión pasa a `0`, sin importar que Lista Nominal/RENAPO/biometría hayan pasado. Cuando el QR sí hace fallar la sesión, `errors` trae una entrada por cada comprobación que no pasó, con esta forma: ```json { "Key": "QR-KYC-001", "Name": "CURP del QR contra OCR", "Category": "KycQrValidation", "Result": false, "Output": "qr=HEHJ050803HDFRRHA9 ocr=CURL041004HVZRSNA3", "Message": "El CURP leído del QR no coincide con el OCR" } ``` | Key | Motivo | | - | - | | QR-KYC-001 | El CURP leído del QR no coincide con el OCR del anverso. | | QR-KYC-002 | El nombre leído del QR no coincide con el OCR del anverso. | | QR-KYC-003 | El rostro embebido en el QR no coincide con el rostro capturado. | ## Ejemplo completo **QR válido (result: 100)** ```json { "attempted": true, "ok": true, "stage": "done", "error": null, "modelo": "G/H", "qr_not_applicable": false, "signature_checked": true, "signature_valid": true, "fields": { "curp": "GALJ900101HDFRRN05", "nombres": "JUAN CARLOS", "primer_apellido": "GARCIA", "segundo_apellido": "LOPEZ", "vigencia": "2019-2029" }, "data_match": { "curp": { "qr": "GALJ900101HDFRRN05", "ocr": "GALJ900101HDFRRN05", "match": true }, "nombre": { "qr": "JUAN CARLOS GARCIA LOPEZ", "ocr": "GARCIA LOPEZ JUAN CARLOS", "match": true } }, "face_match": { "compared": true, "confidence": 99.87, "matched": true, "threshold": 80 } } ``` **QR alterado (result: 0)** ```json { "attempted": true, "ok": true, "stage": "done", "error": null, "modelo": "G/H", "qr_not_applicable": false, "signature_checked": true, "signature_valid": true, "fields": { "curp": "HEHJ050803HDFRRHA9", "nombres": "JOHANN EBLEM", "primer_apellido": "HERNANDEZ", "segundo_apellido": "HERRERIAS", "vigencia": "2024-2034" }, "data_match": { "curp": { "qr": "HEHJ050803HDFRRHA9", "ocr": "CURL041004HVZRSNA3", "match": false }, "nombre": { "qr": "JOHANN EBLEM HERNANDEZ HERRERIAS", "ocr": "CRUZ ROSAS LEONARDO DANIEL", "match": false } }, "face_match": { "compared": true, "confidence": 0.0, "matched": false, "threshold": 80 } } ``` En este caso la sesión termina con `"result": 0` y `errors` trae las tres entradas `QR-KYC-001`, `QR-KYC-002` y `QR-KYC-003`. **Credencial sin QR (result: no afectado)** ```json { "attempted": true, "ok": false, "stage": null, "error": null, "modelo": null, "qr_not_applicable": true, "signature_checked": false, "signature_valid": false, "fields": {}, "data_match": {}, "face_match": { "compared": false, "confidence": 0.0, "matched": false, "threshold": 80 } } ``` La credencial es modelo DEF: no hay QR que leer. `errors` no incluye ninguna entrada de QR y el resultado depende solo del resto de las validaciones. **Solo V3** Esta validación no existe en las sesiones creadas con la V2. **Solo pagas si se lee** 5 tokens extra con `INE` y `CURP` (10 sin ambas), solo cuando el QR se pudo leer. **No todo INE aplica** Solo credenciales modelo G/H (2019+) traen los 2 QR del reverso. **Solo penaliza fraude real** Un QR ilegible no baja el resultado; un QR leído que no coincide, sí.