POST a la URL que configures junto con la información del evento.
Configuración
Para utilizar webhooks, debes:- Definir una URL pública que pueda recibir solicitudes
POST - Configurar un
secretpara validar la autenticidad del webhook - Seleccionar al menos un evento
Debes seleccionar al menos un evento para registrar un webhook.
Eventos disponibles
status_changed
Se dispara cuando cambia el estado general de un expediente (Ej: Pendiente, En Revisión, Completado).
document_submitted
Notifica cuando un documento es enviado o actualizado.
document_verdict
Se dispara cuando un documento recibe un veredicto (Aprobado/Rechazado).
document_verdict_v2
Se dispara cuando un documento recibe un veredicto con el detalle de cada validación aplicada.
channel_changed
Se activa cuando cambia el canal de comunicación o método de verificación.
section_feedback
Notifica cuando se actualiza una sección del expediente con retroalimentación.
document_json_export
Envía la información completa del expediente en formato JSON al finalizar el proceso.
authorized_enrollment
Notifica cuando un representante legal completa su enrolamiento biométrico con estatus AUTORIZADO.
Construye tu receptor de forma tolerante. El cuerpo de los eventos puede crecer con el tiempo: agregamos campos nuevos para dar mejor trazabilidad sin previo cambio de versión. Tu integración debe leer los campos que necesita e ignorar los que no conoce; nunca rechaces un evento por traer un atributo adicional.
Estructura del Request
Headers
{
"content-type": "application/json",
"x-nufi-event": "status_changed",
"x-nufi-signature": "v1=firma_hmac_sha256",
"x-nufi-webhook-timestamp": "timestamp_unix",
"x-nufi-webhook-id": "uuid_del_webhook"
}
Body (Ejemplo)
Se anexan ejemplos para cada tipo de eventostatus_changed
{
"Type": "status_changed",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"Timestamp": "2026-04-07T23:31:09.104111Z",
"User": "4a5d3f24c0a247b88d7432ca25a2f51b",
"NewStatus": "Pendiente de revisión por analista",
"NextResponsible": "Analista",
"ExternalId": ""
}
document_submitted
{
"Type": "document_submitted",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"ExternalId": null,
"Folio": "2026-0077",
"Timestamp": "2026-04-07T23:31:09.7698766Z",
"PreviousStatus": "Ingresado",
"NewStatus": "Recibido"
}
document_verdict
{
"Type": "document_verdict",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"ExternalId": null,
"Timestamp": "2026-04-07T23:31:18.5780469Z",
"Approved": true,
"Comments": "Expediente APROBADO: Se encontró un documento de identificación oficial (Pasaporte) para la persona registrada. No es necesario presentar INE o Licencia si ya existe un Pasaporte válido en el expediente."
}
document_verdict_v2
Incluye el resultado global del veredicto (Approved) y un arreglo Results con el detalle de cada validación ejecutada. Cada elemento contiene:
id: Identificador de la validaciónvalid: Indica si la validación pasó (true) o falló (false)message: Descripción del resultado de la validación
{
"Type": "document_verdict_v2",
"DocumentId": "84796f86-8849-49a6-860d-7719bad639c7",
"ExternalId": null,
"Folio": "2026-0077",
"Timestamp": "2026-06-13T00:14:26.2660673Z",
"Approved": false,
"Results": [
{
"id": "104",
"valid": true,
"message": "Nombre y apellidos del INE coinciden con la captura de datos"
},
{
"id": "456",
"valid": false,
"message": "Se detectaron inconsistencias entre el documento y las fuentes de información consultadas"
},
{
"id": "455",
"valid": false,
"message": "Se detectaron inconsistencias entre los documentos y las fuentes de información consultadas"
},
{
"id": "503",
"valid": false,
"message": "Se detectaron inconsistencias entre los documentos y las fuentes de información consultadas"
},
{
"id": "153",
"valid": false,
"message": "El documento presentado no cumple con los criterios de validación requeridos"
},
{
"id": "451",
"valid": false,
"message": "Se detectaron inconsistencias entre el documento y las fuentes de información consultadas"
},
{
"id": "100",
"valid": true,
"message": "Datos personales presentes en identificación"
},
{
"id": "301",
"valid": false,
"message": "Se detectaron inconsistencias entre los documentos y las fuentes de información consultadas"
},
{
"id": "1001",
"valid": false,
"message": "INE VENCIDA"
},
{
"id": "453",
"valid": false,
"message": "Se detectaron inconsistencias entre el documento y las fuentes de información consultadas"
},
{
"id": "151",
"valid": true,
"message": "RFC, CURP y datos fiscales de la CSF validados correctamente"
},
{
"id": "152",
"valid": true,
"message": "Domicilio fiscal validado correctamente"
},
{
"id": "502",
"valid": true,
"message": "Información de la CSF consistente con QR SAT."
},
{
"id": "156",
"valid": true,
"message": "Nombre y apellidos del INE coinciden con la captura de datos"
},
{
"id": "157",
"valid": false,
"message": "Los datos del documento no coinciden con la información capturada o validada"
}
]
}
channel_changed
{
"Type": "channel_changed",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"Timestamp": "2026-04-07T23:32:03.1556061Z",
"User": "Sistema",
"PreviousChannel": "Sin canal",
"NewChannel": "Validacion",
"ExternalId": ""
}
section_feedback
{
"Type": "section_feedback",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"Timestamp": "2026-04-07T23:32:49.0068553Z",
"User": "soporte@nufi.mx",
"Section": "ConstanciaFiscal",
"Status": "Rechazado",
"Comment": "Documento en B/N",
"ExternalId": ""
}
document_json_export
Envía la información completa del expediente al finalizar el proceso. Estructura general:{
"Type": "document_json_export",
"DocumentId": "27a2e1b1-d3f0-47f3-bf69-fb339c5fd861",
"ExternalId": null,
"Folio": "2026-0042",
"Timestamp": "2026-04-07T23:33:13.1582278Z",
"Data": { ... }
}
Biométrico Veridas — INE
Expediente con validación biométrica usando credencial INE (MX_IDCard_2019). Incluye bloque Ine con resultado de consulta al padrón. El formato del bloque depende de la versión del servicio INE: v1.1 (campos planos) o v4 (respuesta estructurada con detailResponse y response).
Ver payload completo (INE)
Ver payload completo (INE)
{
"Type": "document_json_export",
"DocumentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"ExternalId": null,
"Folio": "2026-0001",
"Timestamp": "2026-08-20T23:52:47.4563328Z",
"Data": {
"ExpedienteId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Folio": "2026-0001",
"TipoPersona": "Persona Física",
"Tramite": "Masivo",
"Secciones": [
"RequiresBiometricValidation",
"BiometricLinkDays:7",
"BiometricMinScore:0.7",
"BiometricMinDocument:0.7",
"BiometricMinSelfie:0.7",
"BiometricMinLifeProof:0.7",
"BiometricMinIntegrity:0.7"
],
"Cliente": "5512345678",
"RFC": "",
"FechaCreacion": "2026-08-20T23:49:46Z",
"FechaRecibido": "2026-08-20T23:49:46Z",
"FechaUltimaModificacion": "2026-08-20T23:51:36Z",
"Estatus": "Aceptado",
"Entidades": [
{
"Tipo": "Persona",
"Referencia": "JUAN CARLOS PEREZ LOPEZ",
"Id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"Datos": {
"Nombre": "JUAN CARLOS",
"ApellidoPaterno": "PEREZ",
"ApellidoMaterno": "LOPEZ",
"CURP": "PELJ850315HDFRRN09",
"RFC": "",
"Nacionalidad": "",
"PaisOrigen": "",
"Correo": "solicitante@ejemplo.com",
"Celular": ""
},
"Validaciones": [
{
"Tipo": "Biométrico",
"Entidad": "Veridas",
"Resultado": true,
"Estatus": "Aceptado",
"Detalles": {
"NombreCompleto": "JUAN CARLOS PEREZ LOPEZ",
"RFC": "",
"CURP": "PELJ850315HDFRRN09",
"Email": "solicitante@ejemplo.com",
"FechaSolicitud": "2026-08-20T23:49:46Z",
"FechaNotificacion": "2026-08-20T23:51:36Z"
},
"BiométricoData": {
"Proveedor": "Veridas",
"Estatus": "FINALIZADO",
"ValidationId": "11111111-2222-3333-4444-555555555555",
"FechaSolicitud": "2026-08-20T23:49:46.3241202Z",
"SesionesDeCaptura": 1,
"IntentosReprobados": 0,
"Veredicto": {
"Estatus": "Aceptado",
"Motivo": "BIOMETRIC_PASSED",
"Fecha": "2026-08-20T23:51:36.8949112Z"
},
"UltimoEvento": {
"Codigo": "ProcessCompleted",
"Mensaje": "The process has been successfully completed",
"Fecha": "2026-08-20T23:51:34.1912117Z"
},
"ResultadoProveedor": {
"data": {
"createdAt": "2026-08-20 23:50:26 +0200",
"data": {
"biometry": {
"challenge": {
"token": "[omitido]"
},
"scores": [
{
"name": "ValidasScoreLifeProof",
"value": 0.9519974674737565
},
{
"name": "ValidasScoreSelfie",
"value": 0.9999407278676543
},
{
"name": "ValidasScorePhotoId",
"value": 0.9999407278676543
}
]
},
"challenges": [
{
"actions": [
"bottom",
"right"
],
"class": "move-head-and-back",
"type": "selfie-alive-pro"
}
],
"contextualData": {
"stats_duration_sap": 5.77,
"stats_tenant": "CasodeUso"
},
"document": {
"nodes": [
{
"fieldName": "Nombre / Name",
"name": "PD_Name_Out",
"text": "JUAN CARLOS"
},
{
"fieldName": "Apellidos / Last Name",
"name": "PD_LastName_Out",
"text": "PEREZ LOPEZ"
},
{
"fieldName": "Primer Apellido / First Last Name",
"name": "PD_LastName1_Out",
"text": "PEREZ"
},
{
"fieldName": "Segundo Apellido / Second Last Name",
"name": "PD_LastName2_Out",
"text": "LOPEZ"
},
{
"fieldName": "Clave de Elector / Elector Key",
"name": "PD_IdentificationNumber_Out",
"text": "PELPJC85031509H600"
},
{
"fieldName": "Fecha de Nacimiento / Date of Birth",
"name": "PD_BirthDate_Out",
"text": "12 01 1996"
},
{
"fieldName": "Sexo / Gender",
"name": "PD_Sex_Out",
"text": "M"
},
{
"fieldName": "Nacionalidad / Nationality",
"name": "PD_Nationality_Out",
"text": "MEX"
},
{
"fieldName": "Estado de Domicilio / State of Residence",
"name": "PD_AddressState_Out",
"text": "16"
},
{
"fieldName": "Municipio de Domicilio / Municipality of Residence",
"name": "PD_AddressMunicipality_Out",
"text": "CIUDAD DE MEXICO"
},
{
"fieldName": "Dirección / Address",
"name": "PD_AddressStreet_Out",
"text": "AV REFORMA 100\nCOL CENTRO 06000"
},
{
"fieldName": "Estado de Nacimiento / State of Birth",
"name": "PD_BirthPlaceState_Out",
"text": "12"
},
{
"fieldName": "Fecha de Validez / Expiration Date",
"name": "DD_ExpirationDate_Out",
"text": "31 12 2035"
},
{
"fieldName": "Año de Emisión/ Date of Expedition",
"name": "DD_ExpeditionDate_Out",
"text": "16 07 2025"
},
{
"fieldName": "Document Number",
"name": "DD_DocumentNumber_Out",
"text": "123456789"
},
{
"fieldName": "MRZ / MRZ",
"name": "DD_MRZ_Out",
"text": "IDMEX1234567893<<98765432101239601123H3512311MEX<01<<19078<3PEREZ<LOPEZ<<JUAN<CARLOS"
},
{
"fieldName": "Año Registro / Registration Date",
"name": "OD_RegistrationDate_Out",
"text": "2014"
},
{
"fieldName": "CURP / CURP",
"name": "OD_CURP_Out",
"text": "PELJ850315HDFRRN09"
},
{
"fieldName": "Código de Identificación de la Credencial / Code Identification Credential",
"name": "OD_IDCredentialCode_Out",
"text": "123456789"
},
{
"fieldName": "País de expedición / Issuing country",
"name": "DD_IssuingCountry_Out",
"text": "MEX"
},
{
"fieldName": "Número OCR / OCR Number",
"name": "OD_OCRNumber_Out",
"text": "9876543210123"
},
{
"fieldName": "Sección / Section",
"name": "OD_Section_Out",
"text": "1264"
},
{
"fieldName": "Número de Emisión / Issue Number",
"name": "OD_EmissionNumber_Out",
"text": "01"
},
{
"fieldName": "FUAR / FUAR",
"name": "OD_FUAR_Out",
"text": "19078"
}
],
"scores": [
{
"name": "ScoreVal-PD_Sex_ID-Value",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_MRZ-Value",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_Out-Value",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_Rel-Value",
"value": 1.0
},
{
"name": "ScoreRel-PD_Sex_CURP-PD_Sex_ID-Text",
"value": 1.0
}
],
"scoresConfiguration": {
"minimumAcceptableAge": 18
}
},
"environment": {
"class": "web-mobile",
"platform": "iOS",
"sdk_information": [
{
"name": "sdk-photo-selfie-capture",
"version": "6.8.1"
},
{
"name": "sdk-document-capture",
"version": "6.8.1"
},
{
"name": "sdk-sap-capture",
"version": "6.8.1"
}
],
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.1 Mobile/15E148 Safari/604.1"
},
"identidasVersion": "1.88.1",
"integrity": {
"scores": [
{
"name": "ValidasScoreDocObverseIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreDocReverseIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreSelfieIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreSelfieAliveProIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreIntegrity",
"value": 1.0
}
]
},
"processInformation": {
"XpressID-BE": "4.10.2",
"XpressID-Web": "2.9.1",
"deviceInformation": {
"browser": "Mobile Safari",
"browserVersion": "26.6.1",
"mobile": true,
"model": "iPhone",
"platform": "iOS",
"platformVersion": "18.7"
},
"endUserIP": "192.0.2.1"
},
"summary": {
"notValidatedScores": null,
"scores": [
{
"name": "ValidationGlobalScore",
"value": 1.0
}
]
}
},
"documentCategory": "IDCard",
"documentId": "11111111-2222-3333-4444-555555555555",
"documentType": "MX_IDCard_2019",
"id": "11111111-2222-3333-4444-555555555555",
"pollAnswers": null,
"serviceMode": "validation",
"state": "on_course",
"total_documents": 1
},
"Code": 0,
"Message": null
},
"Scores": {
"DocumentGlobal": 1.0,
"Selfie": 0.9999407278676543,
"PruebaDeVida": 0.9519974674737565,
"Integridad": 1.0,
"Palancas": {
"ScoreGroup-PrintAttackTest": 0.9979496002197266,
"ScoreGroup-ReplayAttackTest": 0.9979496002197266,
"ScoreGroup-PhotoAuthenticity": 0.9990118874443904
}
},
"Ine": {
"idTransactionClient": "33333333-4444-5555-6666-777777777777",
"curp": "PELJ850315HDFRRN09",
"porcentajeFacial": 99.96,
"validacionFacial": true,
"validacionOcr": true,
"validacionCic": true,
"validacionNombre": true,
"validacionApellidoPaterno": true,
"validacionApellidoMaterno": true,
"validacionAnioRegistro": true,
"validacionAnioEmision": true,
"validacionNumeroEmisionCredencial": true,
"validacionClaveElector": true,
"validacionCurp": true,
"estatusINE": "VIGENTE",
"message": "SOLICITUD DE CONSULTA INE CON ÉXITO.",
"validacionDRL": true,
"reporteExtravio": "SIN REPORTE"
},
"Eventos": [
{
"Code": "ProcessCompleted",
"Type": "info",
"Message": "The process has been successfully completed",
"ValidationId": "11111111-2222-3333-4444-555555555555",
"CaptureSession": 1,
"IsError": false,
"OccurredAt": "2026-08-20T23:51:34.1912117Z"
}
]
}
}
]
}
],
"_Schema": {
"Version": "1.0.0",
"UltimaActualizacion": "2026-08-20T23:52:47Z",
"Compatibilidad": ">=1.0.0"
}
}
}
Bloque Ine — v1.1
Formato plano con validaciones booleanas por campo y estatus registral. Vive dentro de BiometricoData.Ine.
Ver bloque Ine v1.1
Ver bloque Ine v1.1
{
"Ine": {
"idTransactionClient": "33333333-4444-5555-6666-777777777777",
"curp": "PELJ850315HDFRRN09",
"porcentajeFacial": 99.96,
"validacionFacial": true,
"validacionOcr": true,
"validacionCic": true,
"validacionNombre": true,
"validacionApellidoPaterno": true,
"validacionApellidoMaterno": true,
"validacionAnioRegistro": true,
"validacionAnioEmision": true,
"validacionNumeroEmisionCredencial": true,
"validacionClaveElector": true,
"validacionCurp": true,
"estatusINE": "VIGENTE",
"message": "SOLICITUD DE CONSULTA INE CON ÉXITO.",
"validacionDRL": true,
"reporteExtravio": "SIN REPORTE"
}
}
Bloque Ine — v4
Formato estructurado con metadatos de la petición (detailResponse), datos de comparación (respuestaComparacion), situación registral y respuesta facial (facialResponse).
Ver bloque Ine v4
Ver bloque Ine v4
{
"Ine": {
"detailResponse": {
"code": "200",
"severityLevel": "0",
"description": "Ok, peticion satisfactoria",
"actor": "INEService",
"businessMeaning": "Ok, peticion satisfactoria"
},
"response": {
"fechaHoraPeticion": "2026-09-02T16:37:44.45",
"indiceSolicitud": "1234567890123456",
"dataResponse": {
"respuestaSituacionRegistral": {
"tipoSituacionRegistral": "VIGENTE",
"tipoReporteRoboExtravio": null
},
"respuestaComparacion": {
"claveElector": true,
"anioRegistro": true,
"apellidoPaterno": true,
"anioEmision": true,
"numeroEmisionCredencial": true,
"nombre": true,
"curp": true,
"apellidoMaterno": true,
"ocr": true
},
"codigoRespuestaDatos": 0
},
"minutiaeResponse": null,
"facialResponse": {
"codigo": 400,
"similitud1": {
"similitud": "0.0%",
"codigo": 400
},
"similitud2": {
"similitud": null,
"codigo": null
}
},
"tiempoProcesamiento": 975,
"codigoRespuesta": 0
}
}
}
Biométrico Veridas — Pasaporte
Expediente con validación biométrica usando pasaporte mexicano (MX_Passport_YYYY). Incluye campos como OD_CAN_Out, PD_BirthPlace_Out y OD_CURP_Out. No incluye bloque Ine.
Ver payload completo (Pasaporte)
Ver payload completo (Pasaporte)
{
"Type": "document_json_export",
"DocumentId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"ExternalId": null,
"Folio": "2026-0002",
"Timestamp": "2026-08-28T23:52:26.4558755Z",
"Data": {
"ExpedienteId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"Folio": "2026-0002",
"TipoPersona": "Persona Física",
"Tramite": "Masivo",
"Secciones": [
"RequiresBiometricValidation",
"BiometricLinkHours:24",
"BiometricMinScore:0.7",
"BiometricMinDocument:0.7",
"BiometricMinSelfie:0.7",
"BiometricMinLifeProof:0.7",
"BiometricMinIntegrity:0.7"
],
"Cliente": "5512345678",
"RFC": "",
"FechaCreacion": "2026-08-28T23:37:16Z",
"FechaRecibido": "2026-08-28T23:37:16Z",
"FechaUltimaModificacion": "2026-08-28T23:52:26Z",
"Estatus": "Aceptado",
"Entidades": [
{
"Tipo": "Persona",
"Referencia": "JUAN CARLOS PEREZ LOPEZ",
"Id": "d4e5f6a7-b8c9-0123-def0-456789012345",
"Datos": {
"Nombre": "JUAN CARLOS",
"ApellidoPaterno": "PEREZ",
"ApellidoMaterno": "LOPEZ",
"CURP": "PELJ850315HDFRRN09",
"RFC": "",
"Nacionalidad": "",
"PaisOrigen": "",
"Correo": "",
"Celular": ""
},
"Validaciones": [
{
"Tipo": "Biometrico",
"Entidad": "Veridas",
"Resultado": true,
"Estatus": "Aceptado",
"Detalles": {
"NombreCompleto": "JUAN CARLOS PEREZ LOPEZ",
"RFC": "",
"CURP": "PELJ850315HDFRRN09",
"Email": "",
"FechaSolicitud": "2026-08-28T23:37:16Z",
"FechaNotificacion": "2026-08-28T23:52:25Z"
},
"BiometricoData": {
"Proveedor": "Veridas",
"Estatus": "FINALIZADO",
"ValidationId": "22222222-3333-4444-5555-666666666666",
"FechaSolicitud": "2026-08-28T23:37:16.2051093Z",
"SesionesDeCaptura": 1,
"IntentosReprobados": 0,
"Veredicto": {
"Estatus": "Aceptado",
"Motivo": "BIOMETRIC_PASSED",
"Fecha": "2026-08-28T23:52:26.0107342Z"
},
"UltimoEvento": {
"Codigo": "ProcessCompleted",
"Mensaje": "The process has been successfully completed",
"Fecha": "2026-08-28T23:52:24.2594713Z"
},
"ResultadoProveedor": {
"data": {
"createdAt": "2026-08-28 23:49:55 +0200",
"data": {
"biometry": {
"challenge": {
"token": "[omitido]"
},
"scores": [
{
"name": "ValidasScoreLifeProof",
"value": 0.9455895031436727
},
{
"name": "ValidasScoreSelfie",
"value": 0.9984297694608635
},
{
"name": "ValidasScorePhotoId",
"value": 0.9984297694608635
}
]
},
"challenges": [
{
"actions": [
"left",
"top"
],
"class": "move-head-and-back",
"type": "selfie-alive-pro"
}
],
"contextualData": {
"stats_duration_sap": 5.8733,
"stats_tenant": "ClienteDemo_DEV"
},
"document": {
"nodes": [
{
"fieldName": "Nombre / Name",
"name": "PD_Name_Out",
"text": "JUAN CARLOS"
},
{
"fieldName": "Apellidos / Last Names",
"name": "PD_LastName_Out",
"text": "PEREZ LOPEZ"
},
{
"fieldName": "Primer Apellido / First Last Name",
"name": "PD_LastName1_Out",
"text": "PEREZ"
},
{
"fieldName": "Segundo Apellido / Second Last Name",
"name": "PD_LastName2_Out",
"text": "LOPEZ"
},
{
"fieldName": "Fecha de Nacimiento / Date of Birth",
"name": "PD_BirthDate_Out",
"text": "15 03 1985"
},
{
"fieldName": "Sexo / Gender",
"name": "PD_Sex_Out",
"text": "M"
},
{
"fieldName": "Nacionalidad / Nationality",
"name": "PD_Nationality_Out",
"text": "MEX"
},
{
"fieldName": "Tipo / Type",
"name": "PD_PermissionType_Out",
"text": "P"
},
{
"fieldName": "Fecha de Validez / Expiration Date",
"name": "DD_ExpirationDate_Out",
"text": "15 03 2030"
},
{
"fieldName": "País de expedición / Issuing country",
"name": "DD_IssuingCountry_Out",
"text": "MEX"
},
{
"fieldName": "Número de Documento / Document Number",
"name": "DD_DocumentNumber_Out",
"text": "G12345678"
},
{
"fieldName": "Card Access Number (CAN)",
"name": "OD_CAN_Out",
"text": "123456"
},
{
"fieldName": "Observaciones / Observations",
"name": "OD_Observations_Out",
"text": ""
},
{
"fieldName": "Fecha de Expedición / Date of Expedition",
"name": "DD_ExpeditionDate_Out",
"text": "15 03 2020"
},
{
"fieldName": "Lugar de Nacimiento / Place of Birth",
"name": "PD_BirthPlace_Out",
"text": "CIUDAD DE MEXICO, CDMX"
},
{
"fieldName": "MRZ / MRZ",
"name": "DD_MRZ_Out",
"text": "P<MEXPEREZ<LOPEZ<<JUAN<CARLOS<<<<<<<<<<<<<<G123456789MEX8503153M3003158<<<<<<<<<<<<<<04"
},
{
"fieldName": "CURP / CURP",
"name": "OD_CURP_Out",
"text": "PELJ850315HDFRRN09"
}
],
"scores": [
{
"name": "ScoreVal-OD_CAN_Out-Regular",
"value": 1.0
},
{
"name": "ScoreVal-OD_CAN_Rel-Regular",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_MRZ-Value",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_Out-Value",
"value": 1.0
},
{
"name": "ScoreVal-PD_Sex_Rel-Value",
"value": 1.0
}
],
"scoresConfiguration": {
"minimumAcceptableAge": 18
}
},
"environment": {
"class": "web-mobile",
"platform": "iOS",
"sdk_information": [
{
"name": "sdk-photo-selfie-capture",
"version": "6.8.1"
},
{
"name": "sdk-document-capture",
"version": "6.8.1"
},
{
"name": "sdk-sap-capture",
"version": "6.8.1"
}
],
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.1 Mobile/15E148 Safari/604.1"
},
"identidasVersion": "1.88.1",
"integrity": {
"scores": [
{
"name": "ValidasScoreDocObverseIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreSelfieIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreSelfieAliveProIntegrity",
"value": 1.0
},
{
"name": "ValidasScoreIntegrity",
"value": 1.0
}
]
},
"processInformation": {
"XpressID-BE": "4.10.2",
"XpressID-Web": "2.9.1",
"deviceInformation": {
"browser": "Mobile Safari",
"browserVersion": "26.6.1",
"mobile": true,
"model": "iPhone",
"platform": "iOS",
"platformVersion": "18.7"
},
"endUserIP": "192.0.2.1"
},
"summary": {
"notValidatedScores": null,
"scores": [
{
"name": "ValidationGlobalScore",
"value": 1.0
}
]
}
},
"documentCategory": "Passport",
"documentId": "22222222-3333-4444-5555-666666666666",
"documentType": "MX_Passport_YYYY",
"id": "22222222-3333-4444-5555-666666666666",
"pollAnswers": null,
"serviceMode": "validation",
"state": "on_course",
"total_documents": 1
},
"Code": 0,
"Message": null
},
"Scores": {
"DocumentGlobal": 1.0,
"Selfie": 0.9984297694608635,
"PruebaDeVida": 0.9455895031436727,
"Integridad": 1.0,
"Palancas": {
"ScoreGroup-PrintAttackTest": 0.9995332015188116,
"ScoreGroup-ReplayAttackTest": 0.9995332015188116,
"ScoreGroup-PhotoAuthenticity": 0.9983738127507662
}
},
"Eventos": [
{
"Code": "ProcessCompleted",
"Type": "info",
"Message": "The process has been successfully completed",
"ValidationId": "22222222-3333-4444-5555-666666666666",
"CaptureSession": 1,
"IsError": false,
"OccurredAt": "2026-08-28T23:52:24.2594713Z"
}
]
}
}
]
}
],
"_Schema": {
"Version": "1.0.0",
"UltimaActualizacion": "2026-08-28T23:52:26Z",
"Compatibilidad": ">=1.0.0"
}
}
}
authorized_enrollment
{
"Type": "authorized_enrollment",
"DocumentId": "3000f2cc-a26c-4b94-939c-01c679376a11",
"Timestamp": "2026-04-27T23:37:57.2132318Z",
"Source": null,
"CompanyRfc": "PELJ850315XX0",
"CompanyName": "JUAN CARLOS PEREZ LOPEZ",
"PersonId": "a9447718-e565-4109-95b0-9d6bed7869bb",
"FullName": "JUAN CARLOS PEREZ LOPEZ",
"Email": "solicitante@ejemplo.com",
"Phone": "5512345678",
"Rfc": "PELJ850315XX0",
"Curp": "PELJ850315HDFRRN09",
"FaceKeyId": "T000014885",
"EnrollmentRequestAtUtc": "2026-04-27T23:34:27.5485955Z",
"CallbackAtUtc": "2026-04-27T23:34:59.523272Z",
"NotificationAtUtc": "2026-04-27T23:37:56.8825745Z",
"EnrollmentStatus": "AUTORIZADO",
"ExternalId": null
}
Source permite identificar qué sistema creó el expediente. Este valor se devuelve en el webhook para que puedas enrutar o procesar la información según su origen
Validación de firma
Para garantizar que el webhook proviene de NUFI, debes validar la firma utilizando tu secret. Antes de usar el HMACSHA256 deberás hacer un slice para quitar la versión del valor del signature, por defecto viene comov1= y seguido del hash hmac
Generación de la firma:
signedPayload = timestamp + "." + rawBody
signature = HMACSHA256(secret, signedPayload)
timestamp: Headerx-nufi-webhook-timestamprawBody: Body sin modificar (raw)secret: Tu clave privada
JavaScript (Node.js)
const crypto = require("crypto");
function verifyWebhookSignature({ rawBody, signature, timestamp, secret }) {
const signedPayload = `${timestamp}.${rawBody}`;
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(signedPayload, "utf8")
.digest("hex");
// Remover el prefijo "v1=" si existe
const cleanSignature = signature.startsWith("v1=")
? signature.slice(3)
: signature;
return crypto.timingSafeEqual(
Buffer.from(cleanSignature, "hex"),
Buffer.from(expectedSignature, "hex")
);
}
// Express
app.post("/webhook", (req, res) => {
const signature = req.headers["x-nufi-signature"];
const timestamp = req.headers["x-nufi-webhook-timestamp"];
const rawBody = req.rawBody; // IMPORTANTE: usar body crudo
const secret = process.env.NUFI_WEBHOOK_SECRET;
const isValid = verifyWebhookSignature({
rawBody,
signature,
timestamp,
secret
});
if (!isValid) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(rawBody);
console.log("Evento recibido:", event);
res.status(200).send("OK");
});
Python (Flask)
import hmac
import hashlib
from flask import Flask, request, abort
from secrets import compare_digest
app = Flask(__name__)
def verify_webhook_signature(raw_body: bytes, signature: str, timestamp: str, secret: str) -> bool:
signed_payload = f"{timestamp}.{raw_body.decode('utf-8')}"
expected_signature = hmac.new(
key=secret.encode("utf-8"),
msg=signed_payload.encode("utf-8"),
digestmod=hashlib.sha256
).hexdigest()
# Remover el prefijo "v1=" si existe
clean_signature = signature[3:] if signature.startswith("v1=") else signature
return compare_digest(clean_signature, expected_signature)
@app.post("/webhook")
def webhook():
signature = request.headers.get("x-nufi-signature", "")
timestamp = request.headers.get("x-nufi-webhook-timestamp", "")
# Importante: obtener el body crudo sin modificar
raw_body = request.get_data(cache=False, as_text=False)
secret = os.environ.get("NUFI_WEBHOOK_SECRET", "")
if not verify_webhook_signature(raw_body, signature, timestamp, secret):
abort(401, "Invalid signature")
event = request.get_json(force=True, silent=False)
print("Evento recibido:", event)
return ("OK", 200)
C# (.NET / ASP.NET Core)
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class WebhookController : ControllerBase
{
private static bool VerifyWebhookSignature(string rawBody, string signature, string timestamp, string secret)
{
var signedPayload = $"{timestamp}.{rawBody}";
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(signedPayload));
var expectedSignature = Convert.ToHexString(hash).ToLowerInvariant();
// Remover el prefijo "v1=" si existe
var cleanSignature = signature.StartsWith("v1=")
? signature.Substring(3)
: signature;
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(cleanSignature),
Encoding.UTF8.GetBytes(expectedSignature)
);
}
[HttpPost]
[Route("webhook")]
public IActionResult Post()
{
var signature = Request.Headers["x-nufi-signature"].ToString();
var timestamp = Request.Headers["x-nufi-webhook-timestamp"].ToString();
using var reader = new StreamReader(Request.Body, Encoding.UTF8);
var rawBody = reader.ReadToEnd();
var secret = Environment.GetEnvironmentVariable("NUFI_WEBHOOK_SECRET") ?? "";
if (!VerifyWebhookSignature(rawBody, signature, timestamp, secret))
{
return Unauthorized("Invalid signature");
}
// Parsear evento
// var evt = JsonSerializer.Deserialize<JsonElement>(rawBody);
Console.WriteLine($"Evento recibido: {rawBody}");
return Ok("OK");
}
}
PHP (Laravel/Plain PHP)
<?php
function verify_webhook_signature(string $rawBody, string $signature, string $timestamp, string $secret): bool {
$signedPayload = $timestamp . "." . $rawBody;
$expected = hash_hmac('sha256', $signedPayload, $secret);
// Remover el prefijo "v1=" si existe
$cleanSignature = str_starts_with($signature, 'v1=')
? substr($signature, 3)
: $signature;
return hash_equals($cleanSignature, $expected);
}
// Plain PHP
$signature = $_SERVER['HTTP_X_NUFI_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_NUFI_WEBHOOK_TIMESTAMP'] ?? '';
$rawBody = file_get_contents('php://input'); // Body crudo
$secret = getenv('NUFI_WEBHOOK_SECRET') ?: '';
if (!verify_webhook_signature($rawBody, $signature, $timestamp, $secret)) {
http_response_code(401);
echo "Invalid signature";
exit;
}
$event = json_decode($rawBody, true);
error_log("Evento recibido: " . print_r($event, true));
http_response_code(200);
echo "OK";
.png?fit=max&auto=format&n=SrFWYqQUIKuRmdvu&q=85&s=29a9d6074794b17ba1b2d2cd5d208849)