> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Crear Validación KYC

> Iniciar una sesión de verificación KYC para una entidad persona — en la API KYC de gu1 para flujos de verificación de identidad, con ejemplos para create.

## Resumen

Este endpoint crea una nueva sesión de validación KYC para una entidad persona usando un proveedor de integración configurado. Después de crear la validación, recibirás una URL de verificación que puedes compartir con tu cliente para completar la verificación de identidad.

## Diagrama de Flujo Completo

Secuencia desde la creación de la entidad hasta la validación KYC (flujo de producción; en sandbox con números de documento de prueba se omite el paso del proveedor y la API devuelve el resultado mock y los webhooks de inmediato—ver [Datos mock en sandbox](/es/use-cases/kyc/sandbox-mock-data)):

```mermaid theme={null}
sequenceDiagram
    participant Client as Tu Aplicación
    participant API as gu1 API
    participant User as Usuario Final
    participant KYC as Proveedor KYC

    Note over Client,KYC: Paso 1: Crear Entidad Persona
    Client->>API: POST /api/entities
    Note right of Client: type, taxId, name, countryCode
    API-->>Client: 201 Created { entityId }<br/>o 409 si taxId ya existe

    Note over Client,KYC: Paso 2: Crear Validación KYC
    Client->>API: POST /api/kyc/validations
    Note right of Client: entityId, integrationCode
    API->>KYC: Inicializar sesión de verificación
    KYC-->>API: Sesión creada
    API-->>Client: 201 Created<br/>{ id, providerSessionUrl, status: "pending" }

    Note over Client,KYC: Paso 3: Usuario Completa la Verificación
    Client->>User: Enviar providerSessionUrl
    User->>KYC: Abre URL, sube documento, selfie
    KYC->>KYC: Documento + liveness + coincidencia facial
    KYC->>API: Resultado (webhook o sync del proveedor)
    API->>API: Actualizar estado de la validación

    Note over Client,KYC: Paso 4: Webhook al Cliente
    API->>Client: POST tu URL de webhook
    Note right of API: event: kyc.validation_approved<br/>o kyc.validation_rejected<br/>payload: validación completa

    Note over Client,KYC: Paso 5: Opcional – Consultar Estado
    Client->>API: GET /api/kyc/validations/:id
    API-->>Client: 200 OK { status, ... }
```

<Accordion title="Puntos Clave en el Flujo">
  **1. Entidad y taxId duplicado**

  * Crea primero la entidad persona con `POST /api/entities` (incluye `countryCode`). Si el `taxId` ya existe en la organización, la API devuelve **409** y no crea duplicado; usa el ID de la entidad existente.
  * Necesitas un `entityId` existente para crear una validación KYC.

  **2. Código de integración**

  * `global_gueno_validation_kyc` es el código estándar para KYC completo y funciona en sandbox sin configuración adicional.

  **3. URL de verificación**

  * En producción, la respuesta incluye `providerSessionUrl`. Envía esa URL a tu usuario; completan el flujo en la página del proveedor (documento + selfie). La URL es válida hasta `expiresAt`.
  * En **sandbox**, si el documento de la entidad está en la [lista de prueba](/es/use-cases/kyc/sandbox-mock-data), no se usa sesión del proveedor: la API devuelve 201 con estado `pending` y **momentos después** actualiza la validación y envía los webhooks (p. ej. `kyc.validation_approved` o `kyc.validation_rejected`), sin paso del usuario. **Importante:** Debes tener configurado un webhook endpoint para recibir las respuestas - ver [Datos mock en sandbox](/es/use-cases/kyc/sandbox-mock-data).

  **4. Eventos de webhook**

  * Cuando termina la validación, la API envía un webhook a tu URL. El **evento** es uno de: `kyc.validation_approved`, `kyc.validation_rejected`, `kyc.validation_abandoned`, `kyc.validation_expired`, `kyc.validation_cancelled` (no un único evento “completed”). El payload es el objeto de validación completo.
  * También puedes hacer polling a `GET /api/kyc/validations/:id` para actualizaciones de estado.
</Accordion>

## Prerrequisitos

Antes de crear una validación KYC:

1. **La entidad persona debe existir**: Crea una entidad persona usando la [API de Entidades](/api-reference/entities/create)
2. **Integración KYC configurada**: Tu organización debe tener un proveedor de integración KYC activado (ej: `global_gueno_validation_kyc`)
3. **API key válida**: Autentica con tu clave API

<Info>
  **Sandbox vs Producción**: Los entornos sandbox NO requieren configuración de perfil ni preconfiguración. Puedes probar validaciones KYC inmediatamente en sandbox con datos de prueba. Los entornos de producción requieren:

  * Proceso de onboarding de la organización completado
  * Proveedor de integración KYC activado por el equipo de gu1
  * Saldo de crédito suficiente para operaciones KYC

  Para comenzar en sandbox, simplemente usa tu clave API de sandbox - no se necesita configuración adicional.
</Info>

### Datos mock (sandbox)

En sandbox, cuando el documento de la entidad persona (`taxId`) coincide con uno de nuestros **valores de prueba**, la API devuelve un **resultado mock inmediato** (p. ej. aprobado, rechazado, cancelado) y envía los webhooks correspondientes, sin ejecutar una verificación real. El formato del documento no importa (p. ej. `99.990.001` y `99990001` funcionan igual).

Para ver la lista completa de números de documento de prueba por formato (Argentina DNI/CUIT, Brasil CPF/CNPJ), resultados esperados y ejemplos de respuesta, consulta **[Datos mock en sandbox](/es/use-cases/kyc/sandbox-mock-data)**.

## Comportamientos Importantes

### taxId duplicado (POST /entities)

<Warning>
  **¿Qué sucede si llamas a POST /entities con un taxId que ya existe?**

  La API **no** crea una segunda entidad. Devuelve **409 Conflict** con código de error `DUPLICATE_TAX_ID` e incluye en los detalles el `id`, `name` y `type` de la entidad existente.

  **Qué hacer:**

  1. **Opción A – Consultar antes**: Usa `GET /api/entities?taxId=12345678` (o el endpoint by-tax-id) antes de crear. Si existe la entidad, usa su `entityId` para KYC.
  2. **Opción B – Manejar el 409**: Si recibes 409, lee `error.details.existingEntityId` en la respuesta y usa ese `entityId` para tu validación KYC.
  3. **Reutilizar la misma entidad**: Usa una entidad por persona/empresa y crea varias validaciones KYC sobre ese mismo `entityId` si necesitas re-verificación o nuevos intentos.

  **Ejemplo – Verificar antes de crear:**

  ```javascript theme={null}
  // Verificar si la entidad existe
  const existing = await fetch('https://api.gu1.ai/api/entities?taxId=12345678', {
    headers: { 'Authorization': 'Bearer TU_API_KEY' }
  });
  const data = await existing.json();

  let entityId;
  if (data.data && data.data.length > 0) {
    entityId = data.data[0].id; // Usar entidad existente
  } else {
    const createRes = await fetch('https://api.gu1.ai/api/entities', {
      method: 'POST',
      headers: { 'Authorization': 'Bearer TU_API_KEY', 'Content-Type': 'application/json' },
      body: JSON.stringify({ type: 'person', taxId: '12345678', name: 'Juan Pérez', countryCode: 'AR' })
    });
    const created = await createRes.json();
    entityId = created.entity?.id ?? created.data?.id;
  }

  // Crear validación KYC con el entityId
  ```
</Warning>

### Múltiples Validaciones KYC por Entidad

Puedes **crear** múltiples validaciones KYC para la misma entidad:

* Cada validación obtiene un ID y sesión únicos
* Solo la validación **aprobada** más reciente se marca como `isCurrent: true`
* Casos de uso: Re-verificación, validaciones expiradas, intentos fallidos
* Si la entidad ya tiene una validación **abierta** (`pending`, `in_progress` o `in_review`), el create devuelve **`409 VALIDATION_IN_PROGRESS`** con **`activeValidationId`** — cancelá esa validación primero y recién ahí creá de nuevo

<Note>
  **Contrato aditivo:** Los clientes que solo leen `error` y `message` no cambian. `activeValidationId` es metadata opcional en el 409 para evitar un lookup extra antes del cancel.
</Note>

## Solicitud

### Endpoint

```
POST https://api.gu1.ai/api/kyc/validations
```

### Headers

```json theme={null}
{
  "Authorization": "Bearer TU_API_KEY",
  "Content-Type": "application/json"
}
```

### Parámetros de Query (opcionales)

<ParamField query="doubleCheckRenaper" type="boolean">
  En `true`, activa el doble chequeo RENAPER para entidades **Argentina**. En estados terminales la API consulta el registro oficial (datos y, cuando aplica, biometría) y guarda el resultado en metadata. **Solo** si la **verificación OCR KYC** devuelve el estado **`approved`** un fallo de cruce puede rechazar automáticamente la validación; en `in_review` o `rejected` el chequeo es informativo (`enforcementApplied: false`). Requiere entidad de Argentina y credenciales RENAPER configuradas en la organización.
</ParamField>

### Parámetros del Body

Indicá **exactamente uno** de estos identificadores de entidad:

<ParamField body="entityId" type="string">
  El UUID de la entidad persona a verificar

  **Tipo**: `string` (uuid)
</ParamField>

<ParamField body="entityExternalId" type="string">
  Tu ID externo de la entidad (`entities.externalId` en Gu1).
</ParamField>

<ParamField body="entityTaxId" type="string">
  Documento fiscal (CUIT, CPF, DNI, etc.). Gu1 lo resuelve con match normalizado en `entities.tax_id`. La entidad **debe existir** (404 si no hay fila).
</ParamField>

<Info>
  En **sandbox**, `GET /api/entities/by-tax-id/{taxId}` puede devolver una vista previa sintética para números de prueba del catálogo (`sandboxMock: true`) sin fila en DB. **POST /validations** sigue requiriendo una entidad real persistida.
</Info>

<ParamField body="integrationCode" type="string" required>
  El código del proveedor de integración para validación KYC

  **Valor Estándar**: `global_gueno_validation_kyc` (recomendado para la mayoría de casos de uso)

  **Tipo**: `string` (longitud mínima: 1)

  <Note>
    **¿Qué es integrationCode?**

    El `integrationCode` identifica qué integración de proveedor KYC usar para la verificación. Piénsalo como seleccionar el servicio de verificación.

    **Códigos de Integración Disponibles:**

    * `global_gueno_validation_kyc` - **Recomendado** - KYC completo con documento + selfie + coincidencia facial + detección de vida
    * Es posible que se configuren códigos personalizados para tu organización (contacta a soporte)

    **Cómo encontrar tu código de integración:**

    1. Inicia sesión en [gu1 Dashboard](https://app.gu1.ai)
    2. Navega a Configuración → Integraciones → Proveedores KYC
    3. Tu código de integración activo estará listado allí

    En **entornos sandbox**, `global_gueno_validation_kyc` funciona inmediatamente sin configuración.
  </Note>
</ParamField>

<ParamField body="doubleCheckRenaper" type="boolean">
  Igual que el query param. En `true` activa el doble chequeo RENAPER para Argentina. Puede enviarse en el body o como `?doubleCheckRenaper=true`. Si van ambos, prevalece el query.
</ParamField>

<ParamField body="omitWarnings" type="string[]">
  Lista opcional de [códigos de advertencia KYC](/es/use-cases/kyc/warning-risk-codes) (strings exactos). Se guarda en la validación como `metadata.omitWarnings`. Cuando termina la sesión, si la validación quedaría en **`in_review`**, **`warnings` no está vacío** y **todos** los códigos de `warnings` están en esta lista, la API pasa el estado a **`approved`** y conserva las advertencias para UI y auditoría. Si **alguna** advertencia **no** está en `omitWarnings`, el estado sigue **`in_review`**. Si `warnings` está vacío pero el estado es `in_review`, **no** se auto-aprueba. Códigos inválidos o no permitidos en el body devuelven **400**. Si aplica la regla, `metadata.kycOmitWarningsApplied` guarda la marca de tiempo y las advertencias coincidentes.

  Los códigos **no omitibles** (p. ej. `GUENO_CROSS_ENTITY_DUPLICATED`) se rechazan en este campo con **400** y siempre bloquean la auto-aprobación por omit aunque figuren en `warnings`.

  **Tipo**: `string[]` (cada elemento debe ser un código permitido; se ignoran duplicados)
</ParamField>

## Respuesta

### Respuesta Exitosa (201 Created)

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "entityId": "123e4567-e89b-12d3-a456-426614174000",
  "organizationId": "org_abc123",
  "sessionId": "session_xyz789",
  "status": "pending",
  "provider": "kyc_provider",
  "providerSessionUrl": "https://verify.example.com/session_xyz789",
  "isCurrent": true,
  "metadata": {
    "customField": "customValue",
    "doubleChecks": { "renaper": true }
  },
  "createdAt": "2025-01-15T10:30:00Z",
  "updatedAt": "2025-01-15T10:30:00Z"
}
```

Cuando el doble chequeo RENAPER está activo, en creación se guarda `metadata.doubleChecks.renaper: true`. Tras aprobación y ejecución del chequeo, se rellena `metadata.responseDoubleChecks.renaper` (ver [Doble chequeo RENAPER](#doble-chequeo-renaper-argentina)).

### Campos de Respuesta

<ResponseField name="providerSessionUrl" type="string">
  **La URL de verificación para compartir con tu cliente**
</ResponseField>

<ResponseField name="status" type="string">
  Estado actual de la validación. Valores posibles:

  * `pending` - Validación creada, esperando que el cliente inicie
  * `in_progress` - Cliente completando la verificación (llenando formulario)
  * `in_review` - Verificación completada, requiere revisión manual del equipo de compliance
  * `approved` - Verificación exitosa
  * `rejected` - Verificación fallida
  * `expired` - Sesión de verificación expirada (ej. tras 7 días)
  * `abandoned` - Cliente inició pero no completó
  * `cancelled` - Validación cancelada manualmente
</ResponseField>

<Info>
  Tras la aprobación, las claves de medios aparecen dentro de **`decision`**. Para descargar archivos (imágenes, video), usá **`GET /api/kyc/validations/:id/media?key=...`** con `Authorization: Bearer`. Detalle completo: [Obtener medios de la validación KYC](/es/use-cases/kyc/validation-media).
</Info>

## Ejemplo de Solicitud

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch('https://api.gu1.ai/api/kyc/validations', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer TU_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      entityId: '123e4567-e89b-12d3-a456-426614174000',
      integrationCode: 'global_gueno_validation_kyc'
    })
  });

  const validation = await response.json();
  console.log('URL de verificación:', validation.providerSessionUrl);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.gu1.ai/api/kyc/validations',
      headers={
          'Authorization': 'Bearer TU_API_KEY',
          'Content-Type': 'application/json',
      },
      json={
          'entityId': '123e4567-e89b-12d3-a456-426614174000',
          'integrationCode': 'global_gueno_validation_kyc'
      }
  )

  validation = response.json()
  print('URL de verificación:', validation['providerSessionUrl'])
  ```
</CodeGroup>

## Respuestas de Error

### Entidad No Encontrada (404)

```json theme={null}
{
  "error": "ENTITY_NOT_FOUND",
  "message": "Entity not found"
}
```

### Tipo de Entidad Inválido (400)

```json theme={null}
{
  "error": "INVALID_ENTITY_TYPE",
  "message": "KYC validation is only available for person entities"
}
```

### KYC No Configurado (400)

```json theme={null}
{
  "error": "KYC_NOT_CONFIGURED",
  "message": "KYC integration is not configured for this organization. Please contact your administrator."
}
```

### Validación en curso (409)

Cuando la entidad ya tiene una validación abierta (`pending`, `in_progress` o `in_review`), Gu1 sincroniza con la sesión de captura hospedada cuando puede y rechaza un segundo create:

```json theme={null}
{
  "error": "VALIDATION_IN_PROGRESS",
  "message": "Cannot create new KYC validation. There is already a pending validation for this entity. Please cancel or complete the existing validation first.",
  "activeValidationId": "7618e10c-b1b1-408b-b361-1901077ced73"
}
```

**Recuperación:** `409` → `DELETE /api/kyc/validations/{activeValidationId}/cancel` → un solo `POST /api/kyc/validations` nuevo.

Las validaciones terminales (`approved`, `rejected`, `cancelled`, `expired`, `abandoned`) **no** bloquean crear otra.

## Doble chequeo RENAPER (Argentina)

Con `doubleCheckRenaper: true` y entidad de Argentina, en cada estado **terminal** (`approved`, `rejected`, `in_review`) la API ejecuta una verificación cruzada contra el registro oficial (RENAPER) cuando hay datos OCR suficientes. El rechazo automático por RENAPER **solo** aplica si la **verificación OCR KYC** devolvió el estado **`approved`**.

### Cómo enviarlo

* **Body**: `{ "entityId": "...", "integrationCode": "...", "doubleCheckRenaper": true }`
* **Query**: `POST /api/kyc/validations?doubleCheckRenaper=true` con el mismo body. Si van ambos, prevalece el query.

### Dónde se guarda el resultado

En **`metadata.responseDoubleChecks.renaper`**. Los códigos de mismatch (p. ej. trámite y vencimiento) se **añaden** a **`metadata.warnings`** sin reemplazar advertencias previas de la **verificación OCR KYC**. `errorCode` en el objeto `renaper` conserva el primer fallo para compatibilidad; la UI puede listar todos los códigos desde `comparisonResults` y `warnings`.

**Campos de `metadata.responseDoubleChecks.renaper`:**

| Campo                | Tipo    | Descripción                                                                                          |
| -------------------- | ------- | ---------------------------------------------------------------------------------------------------- |
| `verified`           | boolean | `true` si el chequeo pasó.                                                                           |
| `matchResult`        | string  | `"match"` \| `"mismatch"` \| `"error"`.                                                              |
| `verifiedAt`         | string  | ISO timestamp del chequeo.                                                                           |
| `personalNumber`     | string  | Número de trámite desde KYC.                                                                         |
| `idTramitePrincipal` | string  | Número de trámite desde RENAPER.                                                                     |
| `renaperData`        | object  | Respuesta cruda de RENAPER (ver [forma de `renaperData`](#forma-de-renaperdata)).                    |
| `comparisonResults`  | object  | Comparación campo a campo entre OCR y registro (cuando aplica).                                      |
| `renaperBiometric`   | object  | Resultado biométrico ABIS (`validate-dni`): `matchResult`, `score`, `renaperData` (respuesta cruda). |
| `errorCode`          | string  | Presente si falla; ver códigos abajo.                                                                |

### Forma de `renaperData`

Es el **body sin transformar** que devuelve el registro vía ms-providers (`POST …/provider-records/renaper/data`). Gu1 lo reenvía tal cual en `metadata.responseDoubleChecks.renaper.renaperData`. Los nombres de campo están en **snake\_case**; todos son opcionales según lo que devuelva RENAPER en cada consulta.

**Ejemplo (doble chequeo exitoso, `matchResult: "match"`):**

```json theme={null}
{
  "id_tramite_principal": "987654321",
  "id_tramite_tarjeta_reimpresa": "112233445",
  "ejemplar": "A",
  "vencimiento": "2030-05-20",
  "emision": "2015-05-20",
  "apellido": "García",
  "nombres": "Juan",
  "fecha_nacimiento": "1990-01-15",
  "cuil": "20-30123456-9",
  "calle": "Av. Corrientes",
  "numero": "1234",
  "piso": "5",
  "departamento": "B",
  "codigo_postal": "1043",
  "barrio": "San Nicolás",
  "monoblock": "",
  "ciudad": "Ciudad Autónoma de Buenos Aires",
  "municipio": "Comuna 1",
  "provincia": "Buenos Aires",
  "pais": "Argentina",
  "nacionalidad": "Argentina",
  "codigo_fallecido": "",
  "mensaje_fallecido": "",
  "fecha_fallecimiento": "",
  "id_ciudadano": "30123456",
  "codigo": "",
  "mensaje": ""
}
```

**Otros casos habituales:**

| Situación                                                   | `renaperData` típico                                                                          |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| Error antes de obtener datos (ej. `RENAPER_DNI_MISSING`)    | `{}`                                                                                          |
| Servicio no disponible (`RENAPER_VERIFICATION_UNAVAILABLE`) | `{ "error": "…", "code": "SERVICE_UNAVAILABLE" }`                                             |
| Cruce fallido con datos parciales del registro              | Subconjunto de campos (ej. `id_tramite_principal`, `apellido`, `nombres`, `fecha_nacimiento`) |

En sandbox, los mismos valores mock aparecen en [Datos mock de KYC (sandbox)](/es/use-cases/kyc/sandbox-mock-data#ejemplo-de-respuesta-mock-aprobado).

### Forma de `comparisonResults`

Mapa por campo (`dni`, `tramite`, `name`, `ejemplar`, `dateOfBirth`, `expirationDate`). Cada entrada puede incluir:

| Campo               | Tipo    | Descripción                                                              |
| ------------------- | ------- | ------------------------------------------------------------------------ |
| `compared`          | boolean | `true` si se intentó comparar; `false` si se omitió por datos faltantes. |
| `passed`            | boolean | Resultado cuando `compared` es `true`.                                   |
| `skipReason`        | string  | `ocr_missing`, `renaper_missing` o `both_missing` cuando no se comparó.  |
| `ocrValue`          | string  | Valor extraído del OCR (si aplica).                                      |
| `renaperValue`      | string  | Valor del registro RENAPER (si aplica).                                  |
| `similarityPercent` | number  | Solo en `name`: similitud Levenshtein (0–100).                           |
| `threshold`         | number  | Solo en `name`: umbral aplicado (p. ej. 80).                             |
| `errorCode`         | string  | Código de fallo del campo (p. ej. `RENAPER_DNI_NOT_MATCH`).              |

Para **`ejemplar`**, el valor OCR es **`extractedData.ejemplar`** (ver [campos de extractedData](/es/use-cases/kyc/id-verification#campos-de-extracteddata)). La comparación corre cuando existen ambos valores OCR y RENAPER.

**Ejemplo — `extractedData` en una validación KYC aprobada (Argentina):**

```json theme={null}
"extractedData": {
  "documentNumber": "38966181",
  "personalNumber": "00460759387",
  "taxNumber": "20389661814",
  "ejemplar": "C",
  "dateOfBirth": "1995-05-22",
  "expirationDate": "2031-10-17",
  "nationality": "ARG"
}
```

### Forma de `renaperBiometric`

Objeto anidado en `metadata.responseDoubleChecks.renaper.renaperBiometric` cuando la org tiene credenciales biométricas y la sesión KYC aporta selfie. Gu1 envía **una selfie** a `validate-dni`; RENAPER la compara con la foto del DNI en el registro.

| Campo                       | Tipo    | Descripción                                                                                |
| --------------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `verified`                  | boolean | `true` si `resultado.match` del chequeo biométrico ABIS es positivo.                       |
| `matchResult`               | string  | `"match"` \| `"mismatch"` \| `"error"`.                                                    |
| `score`                     | number  | Puntuación devuelta por el chequeo biométrico (si aplica).                                 |
| `verifiedAt`                | string  | ISO timestamp del chequeo biométrico.                                                      |
| `renaperData`               | object  | Respuesta cruda de `validate-dni` (incluye `resultado.match`, `resultado.score`, etc.).    |
| `submittedSelfieRef`        | string  | Referencia de la selfie enviada: ruta de almacenamiento (`kyc/...`) o URL (`https://...`). |
| `submittedSelfieRefKind`    | string  | Formato de `submittedSelfieRef`: `s3_key` (ruta interna) \| `url` (URL pública).           |
| `submittedSelfiePickedFrom` | string  | Origen en `decision`: `liveness_reference_image` o `face_match_target_image`.              |
| `errorCode`                 | string  | Si falla (p. ej. `RENAPER_BIOMETRIC_NOT_MATCH`).                                           |
| `skipReason`                | string  | Si no se ejecutó (p. ej. selfie no disponible).                                            |

### Ejemplo completo de `responseDoubleChecks.renaper`

```json theme={null}
{
  "verified": true,
  "matchResult": "match",
  "personalNumber": "00123456789",
  "idTramitePrincipal": "987654321",
  "verifiedAt": "2026-06-05T14:30:00.000Z",
  "enforcementApplied": true,
  "renaperData": {
    "id_tramite_principal": "987654321",
    "apellido": "García",
    "nombres": "Juan",
    "fecha_nacimiento": "1990-01-15",
    "ejemplar": "A",
    "vencimiento": "2030-05-20"
  },
  "comparisonResults": {
    "dni": {
      "field": "dni",
      "compared": true,
      "passed": true,
      "ocrValue": "30123456",
      "renaperValue": "30123456"
    },
    "tramite": {
      "field": "tramite",
      "compared": true,
      "passed": true,
      "ocrValue": "00123456789",
      "renaperValue": "987654321"
    },
    "name": {
      "field": "name",
      "compared": true,
      "passed": true,
      "ocrValue": "Juan García",
      "renaperValue": "García Juan",
      "similarityPercent": 92,
      "threshold": 80
    },
    "ejemplar": {
      "field": "ejemplar",
      "compared": true,
      "passed": true,
      "ocrValue": "A",
      "renaperValue": "A"
    },
    "dateOfBirth": {
      "field": "dateOfBirth",
      "compared": true,
      "passed": true,
      "ocrValue": "1990-01-15",
      "renaperValue": "1990-01-15"
    }
  },
  "renaperBiometric": {
    "verified": true,
    "matchResult": "match",
    "score": 0.91,
    "verifiedAt": "2026-06-05T14:30:02.000Z",
    "submittedSelfieRef": "kyc/org-id/entity-id/session-id/selfie.jpg",
    "submittedSelfieRefKind": "s3_key",
    "submittedSelfiePickedFrom": "liveness_reference_image",
    "renaperData": {
      "resultado": {
        "match": true,
        "score": 0.91
      }
    }
  }
}
```

`renaperBiometric` y entradas en `comparisonResults` pueden omitirse según credenciales, datos OCR o disponibilidad de selfie.

### Códigos de error (cuando falla RENAPER)

El motivo del rechazo es un **código** en `metadata.warnings` y en `metadata.responseDoubleChecks.renaper.errorCode`. La UI debe traducir estos códigos.

| Código                             | Significado                                                                                                                                                      |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RENAPER_DNI_MISSING`              | No se obtuvo número de documento (DNI) en la verificación.                                                                                                       |
| `RENAPER_GENDER_MISSING`           | Falta género (M/F) para llamar a RENAPER.                                                                                                                        |
| `RENAPER_VERIFICATION_UNAVAILABLE` | No se pudo completar la verificación cruzada (ej. error de red). Reintentar.                                                                                     |
| `RENAPER_DNI_NOT_MATCH`            | El número de documento no coincide con el registro oficial.                                                                                                      |
| `RENAPER_TRAMITE_DATA_MISSING`     | Faltan datos para comparar el número de trámite.                                                                                                                 |
| `RENAPER_TRAMITE_ID_NOT_MATCH`     | El **número de trámite** del documento no coincide con el registro (ejemplar anterior, vencido o reemitido; la persona debe verificar de nuevo con DNI vigente). |
| `RENAPER_NAME_NOT_MATCH`           | El nombre del OCR no alcanza el 80% de similitud con el registro RENAPER.                                                                                        |
| `RENAPER_EJEMPLAR_NOT_MATCH`       | El ejemplar del DNI no coincide con el registro RENAPER.                                                                                                         |
| `RENAPER_DOB_NOT_MATCH`            | La fecha de nacimiento del OCR no coincide con RENAPER.                                                                                                          |
| `RENAPER_EXPIRY_NOT_MATCH`         | La fecha de vencimiento del OCR no coincide con RENAPER.                                                                                                         |
| `RENAPER_BIOMETRIC_NOT_MATCH`      | La selfie no coincide con la foto del DNI en el registro biométrico.                                                                                             |
| `RENAPER_BIOMETRIC_UNAVAILABLE`    | No se pudo completar el chequeo biométrico (red, credenciales o servicio).                                                                                       |

### Cuándo RENAPER aplica enforce (rechazo automático)

| Estado de la verificación OCR KYC                                                                  | ¿RENAPER se ejecuta?                      | ¿Puede rechazar por RENAPER?                              |
| -------------------------------------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------------- |
| **`approved`** (aprobación directa)                                                                | Sí                                        | **Sí** — fallo de cruce → `rejected`                      |
| **`in_review`**                                                                                    | Sí                                        | **No** — informativo; el equipo decide en revisión manual |
| **`rejected`** (rechazo de la verificación OCR o reglas Gu1)                                       | Sí (si hay OCR)                           | **No** — informativo; deja datos en metadata              |
| **Aprobación manual** desde `in_review` ([`POST …/approve`](/es/use-cases/kyc/approve-validation)) | **No** (reutiliza el chequeo ya guardado) | **No** — decisión humana; no se re-ejecuta el cruce       |

En todos los casos con consulta activa, **datos** y **biometría** (cuando aplica) quedan en `metadata.responseDoubleChecks.renaper` (`comparisonResults`, `renaperBiometric`). En `in_review` y `rejected` los códigos RENAPER con mismatch se agregan a `warnings` junto con las advertencias de la verificación OCR.

## Próximos Pasos

Después de crear una validación:

1. **Extrae la URL de verificación** de `providerSessionUrl`
2. **Comparte la URL con tu cliente** vía email, SMS o en tu app
3. **Configura endpoint webhook** para recibir notificaciones de finalización
4. **Monitorea el estado de validación** usando el ID de validación
5. **Tras la aprobación**, leé las claves en `decision` y descargá archivos — ver [Obtener medios de la validación KYC](/es/use-cases/kyc/validation-media)

<CardGroup cols={2}>
  <Card title="Obtener URL de KYC" icon="link" href="/es/use-cases/kyc/get-kyc-url">
    Aprende cómo recuperar la URL
  </Card>

  <Card title="Integración Webhook" icon="webhook" href="/es/use-cases/kyc/webhook-integration">
    Configura notificaciones webhook
  </Card>
</CardGroup>
