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

# Modelos de datos y esquemas JSON de la API

> Esquemas JSON de cada informe de Didit: NFC, ID, Liveness, Face Match, AML, IP, POA, teléfono, email, registro KYB, documentos y personas clave.

## Descripción general

Cada informe por función sigue la estructura del serializador V3 definida en `service-didit-verification`. El mismo objeto aparece en tres lugares, así que el esquema que ves aquí es la única fuente de verdad para todos ellos:

* `GET /v3/session/{sessionId}/decision/`: cada función se devuelve como un array con nombre en plural (`id_verifications[]`, `nfc_verifications[]`, `liveness_checks[]`, `face_matches[]`, `poa_verifications[]`, `phone_verifications[]`, `email_verifications[]`, `aml_screenings[]`, `ip_analyses[]`, `database_validations[]`, `questionnaire_responses[]`, `signatures[]`, `bank_verifications[]` (consulta [Métodos de verificación bancaria](https://docs.didit.me/es/core-technology/bank-verification/verification-methods.md#consultar-el-método-en-los-resultados)) y los equivalentes de KYB `registry_checks[]`, `document_verifications[]`, `key_people_checks[]`).
* Payloads de webhook (`status.updated`, `data.updated`): la misma estructura dentro del envoltorio `decision`.
* APIs independientes: las respuestas de un solo objeto (Búsqueda facial, Estimación de edad, Autenticación biométrica) reutilizan el mismo conjunto de campos.

> [!NOTE]
>
> V3 introdujo los flujos de trabajo multiinstancia: cada objeto de función incluye un `node_id` que vincula el informe al nodo del grafo del flujo que lo generó. Los endpoints V2 (en singular: `kyc`, `face`, `aml`, etc.) siguen siendo retrocompatibles, pero solo devuelven la primera instancia.

## Campos comunes

Cada objeto de informe expone lo siguiente:

| Campo | Tipo | Descripción |
| - | - | - |
| `status` | string | Estado del ciclo de vida a nivel de función: uno de los valores de [Enum de estados](#referencia-de-los-valores-de-estado). Origen: `common/config/choices.py:FeatureStatusChoices` (líneas 343-348). El `status` de nivel superior de la sesión padre usa el enum de sesión, más amplio (`StatusChoices`, líneas 106-117). |
| `node_id` | string \| null | Identificador del nodo del grafo del flujo. Se rellena en los flujos V3 multiinstancia; `null` en las sesiones heredadas de una sola función. |
| `warnings` | array de [objetos de advertencia](#objeto-de-advertencia) | Señales de riesgo filtradas para esta función y este `node_id`. Las devuelve `Session.get_logs(...)` (`sessions/models/session.py:1611`). |

Los campos multimedia (`portrait_image`, `front_image`, `document_file`, …) son URLs prefirmadas con un periodo de validez limitado: descárgalos cuanto antes en lugar de guardar la URL. Los ejemplos los muestran como `https://<media-host>/...`.

## Objeto de advertencia

Se devuelve en cada array `warnings[]`. Esquema de `logs/serializers/log.py:8-65` (`LogV3Serializer`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `feature` | string (enum) | No | Función que emitió la advertencia. Valores de `LogWarningChoices` (`common/config/choices.py:190-204`): `ID_VERIFICATION`, `NFC`, `LIVENESS`, `FACEMATCH`, `PROOF_OF_ADDRESS`, `PHONE`, `EMAIL`, `AML`, `LOCATION`, `DATABASE_VALIDATION`, `QUESTIONNAIRE`, `KYB_REGISTRY`, `KYB_DOCUMENTS`, `KYB_KEY_PEOPLE`. | `"ID_VERIFICATION"` |
| `risk` | string | No | Código de riesgo estable (p. ej., `DOCUMENT_EXPIRED`, `LOW_LIVENESS_SCORE`). Valores de `logs/choices.py:RiskChoices`. Se usa como clave en las tablas de descripciones. | `"DOCUMENT_EXPIRED"` |
| `additional_data` | object \| null | Sí | Contexto específico del riesgo (p. ej., umbrales de puntuación, campos coincidentes). La estructura varía según el código de riesgo. | `{ "score": 42.1, "threshold": 70 }` |
| `log_type` | string (enum) | No | Uno de `error`, `warning`, `information`. De `LogTypeChoices` (`common/config/choices.py:207-210`). | `"error"` |
| `short_description` | string | No | Etiqueta legible del riesgo. De `logs/choices.py:RISK_SHORT_DESCRIPTIONS`. | `"Document expired"` |
| `long_description` | string | No | Explicación legible más extensa, adecuada para interfaces dirigidas al usuario final. De `logs/choices.py:RISK_LONG_DESCRIPTIONS`. | `"The document's expiration date has passed, rendering it no longer valid for use."` |
| `node_id` | string \| null | Sí | Nodo del grafo del flujo para el que se generó la advertencia. `null` en los registros V2 heredados sin `node_id`. | `"first_id_verification"` |

```json theme={null}
{
  "feature": "ID_VERIFICATION",
  "risk": "DOCUMENT_EXPIRED",
  "additional_data": null,
  "log_type": "error",
  "short_description": "Document expired",
  "long_description": "The document's expiration date has passed, rendering it no longer valid for use.",
  "node_id": "first_id_verification"
}
```

## Objetos de informe

Las secciones restantes describen cada objeto de informe por función. El texto de los encabezados H3 se mantiene estable a propósito para que otros documentos puedan enlazarlos directamente.

### Verificación de identidad

Se devuelve por cada documento de KYC/identidad que envía un usuario. Aparece como `id_verifications[]` en `GET /v3/session/{sessionId}/decision/` y dentro del campo `kyc` de las respuestas V2. Fuente: `kyc/serializers/kyc.py:383-414` (`IDVerificationV3Serializer`, que extiende `IDVerificationV2Serializer` en `kyc/serializers/kyc.py:320-380`).

| Campo | Tipo | Admite nulo | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `document_type` | string | Sí | Clase de documento legible (`Passport`, `Identity Card`, `Driver's License`, `Residence Permit`, `Health Insurance Card`, `Tax Card`, `Social Security Card`, `Work Permit`, `Visa`, `Public Service Card`, `Birth Certificate`, `Firearm License`, `Other`). Fuente: `DOC_TYPE_MAPPING` (`common/config/choices.py:1275-1289`). | `"Passport"` |
| `document_subtype` | string | Sí | Código de subtipo de documento del registro de documentos de Didit, filtrado según lo que acepta la configuración de documentos del flujo. Los documentos específicos de una región incluyen la región. Lista completa de códigos: [Subtipos de documento](https://docs.didit.me/es/core-technology/id-verification/document-subtypes-id-verification.md). | `"QUEENSLAND_DRIVER_LICENSE_GENERIC"` |
| `document_number` | string | Sí | Número de documento extraído por OCR. | `"AB1234567"` |
| `personal_number` | string | Sí | Identificador personal/nacional extraído por OCR. | `"99999999R"` |
| `portrait_image` | string (URL) | Sí | URL prefirmada del recorte del rostro. | `"https://<media-host>/.../portrait.jpg?..."` |
| `front_image` | string (URL) | Sí | URL prefirmada del anverso del documento procesado. | `"https://<media-host>/.../front.jpg?..."` |
| `front_video` | string (URL) | Sí | URL prefirmada del video de captura del anverso (cuando está disponible). | `"https://<media-host>/.../front.mp4?..."` |
| `back_image` | string (URL) | Sí | URL prefirmada del reverso del documento procesado. | `"https://<media-host>/.../back.jpg?..."` |
| `back_video` | string (URL) | Sí | URL prefirmada del video de captura del reverso. | `null` |
| `full_front_image` | string (URL) | Sí | Captura del anverso sin recortar (fotograma completo). | `"https://<media-host>/.../full_front.jpg?..."` |
| `full_back_image` | string (URL) | Sí | Captura del reverso sin recortar (fotograma completo). | `null` |
| `front_image_camera_front` | string (URL) | Sí | Imagen de la cámara frontal tomada al mismo tiempo que el anverso del documento. | `null` |
| `back_image_camera_front` | string (URL) | Sí | Imagen de la cámara frontal tomada al mismo tiempo que el reverso del documento. | `null` |
| `front_image_camera_front_face_match_score` | float (0-100) | Sí | Similitud entre el retrato del documento y la captura de la cámara frontal. | `null` |
| `back_image_camera_front_face_match_score` | float (0-100) | Sí | Igual que el anterior, pero para la captura del reverso. | `null` |
| `document_selfie_face_matches` | array | Sí | Sesiones anteriores o entradas de la lista de bloqueo facial que coinciden con la selfie tomada durante la captura del documento. Mismo formato de entrada que `liveness_checks[].matches`. `null` cuando la búsqueda no se ejecutó, `[]` cuando no hubo coincidencias. | `null` |
| `front_image_quality_score` | object | Sí | Métricas de calidad de la imagen del anverso: puntuaciones de 0 a 100 (`focus_score`, `brightness_score`, `resolution_score`, `overall_score`), además de `brightness_issue` (`ok`, `too_dark`, `too_bright`) e `is_document_fully_visible` (booleano). | `{ "focus_score": 91.0, "overall_score": 88.5 }` |
| `back_image_quality_score` | object | Sí | Misma estructura que `front_image_quality_score`. | `null` |
| `date_of_birth` | string (YYYY-MM-DD) | Sí | Fecha de nacimiento extraída por OCR. | `"1990-05-12"` |
| `age` | integer | Sí | Edad calculada en años en el momento de la extracción. | `35` |
| `expiration_date` | string (YYYY-MM-DD) | Sí | Fecha de caducidad del documento. | `"2032-05-11"` |
| `date_of_issue` | string (YYYY-MM-DD) | Sí | Fecha de expedición del documento. | `"2022-05-11"` |
| `issuing_state` | string (ISO 3166-1 alpha-3) | Sí | Código del país emisor. | `"ESP"` |
| `issuing_state_name` | string | Sí | Nombre localizado del país emisor. | `"Spain"` |
| `first_name` | string | Sí | Nombre(s) de pila extraído(s) por OCR. | `"María"` |
| `last_name` | string | Sí | Apellido(s) extraído(s) por OCR. | `"García López"` |
| `full_name` | string | Sí | Nombre completo normalizado (proporcionado por el proveedor). | `"María García López"` |
| `gender` | string | Sí | `M`, `F` u otro valor proporcionado por el proveedor. | `"F"` |
| `address` | string | Sí | Línea de dirección sin procesar extraída por OCR. | `"Calle Mayor 1, 28001 Madrid"` |
| `formatted_address` | string | Sí | Dirección geocodificada/formateada (cuando se puede analizar). | `"Calle Mayor 1, 28001 Madrid, Spain"` |
| `parsed_address` | object | Sí | Dirección estructurada y geocodificada: `street_1`, `street_2`, `city`, `region`, `country`, `postal_code`, `address_type`, `formatted_address`, `document_location` (`{latitude, longitude}`), `raw_results`, `is_best_match`. Fuente: `kyc/utils/address.py:147-197`. | `{ "street_1": "Calle Mayor 1", "city": "Madrid", "postal_code": "28001", "country": "ES" }` |
| `place_of_birth` | string | Sí | Lugar de nacimiento extraído por OCR. | `"Madrid"` |
| `marital_status` | string | Sí | Cuando se puede extraer. | `null` |
| `nationality` | string (ISO 3166-1 alpha-3) | Sí | Nacionalidad extraída por OCR. | `"ESP"` |
| `extra_fields` | object | Sí | Campos específicos del tipo de documento que no cubre el esquema canónico (por ejemplo, las categorías del permiso de conducir). | `{ "DL Class": "B" }` |
| `mrz` | object | Sí | Campos de la MRZ analizados, cuando existe (`document_number`, `birth_date`, `expiry_date`, `surname`, `given_names`, …). | `{ "document_number": "AB1234567", "surname": "GARCIA", "given_names": "MARIA" }` |
| `extra_files` | array de strings (URL) | No | URL prefirmadas de cualquier archivo adicional subido. | `[]` |
| `matches` | array de objetos | No | Coincidencias de documentos entre sesiones. Cada elemento: `{ session_id, session_number, vendor_data, verification_date, user_details: { name, document_type, document_number }, status, is_blocklisted, api_service, front_image_url }`. `front_image_url` es una URL prefirmada. | `[]` |
| `verification_method` | string | No | Qué [método de verificación de identidad](https://docs.didit.me/es/core-technology/id-verification/verification-methods.md) generó esta fila: `document`, `id_lookup` o `wallet`. Siempre es `document` para un documento fotografiado, incluidas todas las sesiones creadas antes de que existieran los demás métodos. | `"id_lookup"` |
| `assurance` | string | No | Nivel de garantía derivado de `verification_method`: `documentary`, `data_match` o `cryptographic`. | `"data_match"` |
| `wallet_provider` | string \| null | Sí | ID de wallet del catálogo cuando una wallet generó esta fila (`mitid`, `bankid_se`, `itsme`, ...). `null` en caso contrario. | `"mitid"` |
| `fallback_from` | object \| null | Sí | Por qué un método distinto del documento terminó el paso de identidad: `{ method, reason, action }`. Se establece en la fila rechazada cuando falló una consulta o un inicio de sesión con wallet y el interruptor del país era `decline`. El staging actual también lo conserva en la verificación de documento resultante tras un fallback; confirma su despliegue en producción. `null` cuando no hay registrado ningún fallo previo de un método distinto del documento. | `{ "method": "id_lookup", "reason": "no_match", "action": "decline" }` |
| `id_lookup` | object \| null | Sí | Evidencia de la fuente, presente solo cuando `verification_method` es `id_lookup`: `source` (la fuente exacta consultada: un registro gubernamental en la mayoría de los países y, en algunos, un archivo de una agencia de crédito o de registros residenciales), `checked_at`, `attempts`, `max_attempts`, `outcome` (`match`, `partial_match`, `no_match`, `provider_error`, `format_rejected`), `comparison[]` (`{ field, label, provided, record, result }`; `field` es uno de `identification_number`, `full_name`, `date_of_birth`, `address`, y `result` es `match`, `partial` o `no_match`; las versiones anteriores pueden incluir una fila `provider` con `error`), `source_errors[]` (staging actual: diagnósticos de la fuente por separado; confirma su despliegue en producción), `registry_portrait` (URL prefirmada, solo para las fuentes que devuelven una) y `face_match_score`. | ver más abajo |
| `wallet_verification` | object \| null | Sí | Evidencia de la credencial, presente solo cuando `verification_method` es `wallet`: `provider`, `provider_name`, `issuing_authority`, `issuing_country`, `credential_type`, `level_of_assurance` (`low`, `substantial`, `high`), `verified_at`, `signature_valid`, `attributes` (lo que compartió la wallet), `portrait` (URL prefirmada cuando la wallet comparte uno) y `face_match_score`. | ver más abajo |
| `document_liveness` | object \| null | Sí | Puntuaciones de prueba de vida del documento por tipo de fraude (`portrait_replace`, `printed_copy`, `screen_replay`), que se informan tanto si se activó una advertencia como si no. Cada una contiene: `score` (0-100, un valor más alto indica mayor probabilidad de que sea auténtico; corresponde al lado con la puntuación más baja, que es el valor que usó la decisión), `front`, `back`, `decline_threshold`, `review_threshold` y `bucket` (`approve`, `review`, `decline` o `null`). Los umbrales y el bucket se guardan en el momento de la evaluación; los tres son `null` cuando no hay evidencia histórica de la evaluación, mientras que las puntuaciones almacenadas siguen visibles. `null` cuando la comprobación no se ejecutó. Consulta [Puntuaciones de prueba de vida del documento](https://docs.didit.me/es/core-technology/id-verification/report-id-verification.md#puntuaciones-de-prueba-de-vida-del-documento). Solo V3. | `{ "portrait_replace": { "score": 96.46, "bucket": "approve" } }` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_id_verification"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |
| `region` | string | Sí | Región o estado del país emisor, cuando el documento lo indica. | `"CA"` |
| `extracted_data` | object | Sí | Instantánea de los datos extraídos del documento que se mostraron a la persona para que los revisara, guardada junto a los valores confirmados para que puedas compararlos. `null` cuando no se pidió a la persona que los revisara. | |
| `barcodes` | array de objetos | No | Datos leídos de los códigos de barras del documento, con una entrada por código de barras que incluye `type`, `position`, `data`, `data_raw` y `side`. `[]` cuando no hay ninguno. | `[]` |

```json theme={null}
{
  "status": "Approved",
  "document_type": "Passport",
  "document_subtype": "PASSPORT_GENERIC",
  "document_number": "AB1234567",
  "personal_number": "99999999R",
  "portrait_image": "https://<media-host>/.../portrait.jpg?signature=...",
  "front_image": "https://<media-host>/.../front.jpg?signature=...",
  "front_video": null,
  "back_image": "https://<media-host>/.../back.jpg?signature=...",
  "back_video": null,
  "full_front_image": "https://<media-host>/.../full_front.jpg?signature=...",
  "full_back_image": null,
  "front_image_camera_front": null,
  "back_image_camera_front": null,
  "front_image_camera_front_face_match_score": null,
  "back_image_camera_front_face_match_score": null,
  "front_image_quality_score": {
    "focus_score": 91.0,
    "brightness_score": 88.0,
    "brightness_issue": "ok",
    "is_document_fully_visible": true,
    "resolution_score": 95.0,
    "overall_score": 88.5
  },
  "back_image_quality_score": null,
  "date_of_birth": "1990-05-12",
  "age": 35,
  "expiration_date": "2032-05-11",
  "date_of_issue": "2022-05-11",
  "issuing_state": "ESP",
  "issuing_state_name": "Spain",
  "first_name": "María",
  "last_name": "García López",
  "full_name": "María García López",
  "gender": "F",
  "address": "Calle Mayor 1, 28001 Madrid",
  "formatted_address": "Calle Mayor 1, 28001 Madrid, Spain",
  "parsed_address": { "street_1": "Calle Mayor 1", "street_2": null, "city": "Madrid", "region": "Madrid", "postal_code": "28001", "country": "ES", "address_type": "Calle" },
  "place_of_birth": "Madrid",
  "marital_status": null,
  "nationality": "ESP",
  "extra_fields": {},
  "mrz": {
    "document_number": "AB1234567",
    "surname": "GARCIA",
    "given_names": "MARIA",
    "birth_date": "900512",
    "expiry_date": "320511"
  },
  "extra_files": [],
  "matches": [],
  "node_id": "first_id_verification",
  "verification_method": "document",
  "assurance": "documentary",
  "wallet_provider": null,
  "fallback_from": null,
  "id_lookup": null,
  "wallet_verification": null,
  "document_liveness": {
    "portrait_replace": {
      "score": 96.46,
      "front": 96.46,
      "back": 98.2,
      "decline_threshold": 35,
      "review_threshold": 70,
      "bucket": "approve"
    },
    "printed_copy": {
      "score": 91.2,
      "front": 91.2,
      "back": 93.7,
      "decline_threshold": 35,
      "review_threshold": 77,
      "bucket": "approve"
    },
    "screen_replay": {
      "score": 99.9,
      "front": 99.9,
      "back": 99.5,
      "decline_threshold": 30,
      "review_threshold": 70,
      "bucket": "approve"
    }
  },
  "warnings": []
}
```

El mismo objeto con un método distinto del documento. Solo cambian las claves específicas del método: todo lo que completa la lectura de un documento se rellena, en su lugar, a partir del registro oficial o de los atributos de la wallet, y las claves que no aplican son `null`.

```json theme={null}
{
  "status": "Approved",
  "issuing_state": "ZAF",
  "first_name": "Thabo",
  "last_name": "Mokoena",
  "full_name": "Thabo Mokoena",
  "date_of_birth": "1991-06-15",
  "personal_number": "9106155043088",
  "node_id": "first_id_verification",
  "verification_method": "id_lookup",
  "assurance": "data_match",
  "wallet_provider": null,
  "fallback_from": null,
  "id_lookup": {
    "source": "Department of Home Affairs",
    "checked_at": "2026-09-04T09:12:44Z",
    "attempts": 1,
    "max_attempts": 2,
    "outcome": "match",
    "comparison": [
      { "field": "identification_number", "label": "ID number", "provided": "9106155043088", "record": "9106155043088", "result": "match" },
      { "field": "full_name", "label": "Full name", "provided": "Thabo Mokoena", "record": "Thabo Mokoena", "result": "match" },
      { "field": "date_of_birth", "label": "Date of birth", "provided": "1991-06-15", "record": "1991-06-15", "result": "match" }
    ],
    "registry_portrait": "https://<media-host>/.../registry_portrait.jpg?signature=...",
    "face_match_score": 96.4
  },
  "wallet_verification": null,
  "warnings": []
}
```

```json theme={null}
{
  "status": "Approved",
  "issuing_state": "DNK",
  "first_name": "Freja",
  "last_name": "Nielsen",
  "full_name": "Freja Nielsen",
  "date_of_birth": "1988-03-02",
  "node_id": "first_id_verification",
  "verification_method": "wallet",
  "assurance": "cryptographic",
  "wallet_provider": "mitid",
  "fallback_from": null,
  "id_lookup": null,
  "wallet_verification": {
    "provider": "mitid",
    "provider_name": "MitID",
    "issuing_authority": "Danish Agency for Digital Government",
    "issuing_country": "DNK",
    "credential_type": "person_identification",
    "level_of_assurance": "substantial",
    "verified_at": "2026-09-04T09:12:44Z",
    "signature_valid": true,
    "attributes": {
      "full_name": "Freja Nielsen",
      "date_of_birth": "1988-03-02",
      "cpr_alias": "b0f1c2d3-e4f5-4678-9abc-def012345678"
    },
    "portrait": null,
    "face_match_score": null
  },
  "warnings": []
}
```

### Verificación NFC

Se devuelve por cada lectura de chip de un documento de identidad: un chip de ePassport o eID conforme a ICAO 9303, o una tarjeta My Number de Japón leída mediante JPKI (`chip_protocol: "jpki"`). Aparece como `nfc_verifications[]` en `GET /v3/session/{sessionId}/decision/` (uno por cada registro KYC principal). Fuente: `kyc/serializers/epassport.py:121-139` (`NFCV3Serializer`, que extiende `NFCV2Serializer` en `kyc/serializers/epassport.py:83-118`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `portrait_image` | string (URL) | Sí | URL prefirmada de la imagen facial extraída del chip. | `"https://<media-host>/.../nfc_portrait.jpg?..."` |
| `signature_image` | string (URL) | Sí | URL prefirmada de la imagen de la firma extraída del chip (cuando está almacenada en el chip). | `null` |
| `chip_data` | object | Sí | Datos personales extraídos de los Data Groups del chip, aplanados (`kyc/utils/epassport.py:165-212`): `dgs` (Data Groups leídos), `surname`, `name`, `country`, `nationality`, `birth_date` (`YYYY-MM-DD`), `expiry_date` (`YYYY-MM-DD`), `sex` (`M`/`F`), `document_type` (código de documento de la MRZ), `document_number`, `optional_data`, dígitos de control de la MRZ (`birth_date_hash`, `expiry_date_hash`, `document_number_hash`, `optional_data_hash`, `final_hash`), `mrz_string`, `mrz_type` (`TD1`/`TD2`/`TD3`); además, `place_of_birth` y `address` (y `full_name` / `full_name_non_latin` para nombres no latinos) cuando el chip contiene DG11; en caso contrario, esas claves no aparecen. `null` cuando se omitió el paso NFC. | `{ "document_number": "AB1234567", "name": "MARIA" }` |
| `authenticity` | object | Sí | `{ sod_integrity, dg_integrity }`; `null` en una lectura JPKI. `sod_integrity` valida que la firma del Document Security Object (SOD) se encadena hasta una CSCA válida del país emisor (y que el DSC no está revocado ni expirado); `dg_integrity` valida que los hashes de cada Data Group coinciden con el SOD. Si ambos son `true`, el chip es auténtico y no ha sido manipulado. | `{ "sod_integrity": true, "dg_integrity": true }` |
| `certificate_summary` | object | Sí | Resumen del certificado del firmante del documento (`kyc/utils/epassport.py:338-348`): `issuer`, `subject`, `serial_number` (entero), `not_valid_before`, `not_valid_after` (`YYYY-MM-DD HH:MM:SS`), además de un objeto `validation` `{ csca_verified, dsc_revoked, dsc_expired, csca_expired }` (`kyc/views/epassport.py:86`). | `{ "issuer": "Common Name: CSCA SPAIN, Country: ES", "not_valid_after": "2031-02-18 10:21:11" }` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_nfc"` |
| `is_nfc_skipped` | boolean | No | `true` cuando este paso NFC se omitió explícitamente en lugar de leerse; `skip_reason` indica el motivo. | `false` |
| `skip_reason` | string | Sí | Motivo por el que se omitió el paso; solo se establece cuando `is_nfc_skipped` es `true`. Uno de `USER_SKIPPED`, `DOCUMENT_WITHOUT_CHIP`, `CHIP_CERTIFICATE_UNAVAILABLE`, `DEVICE_WITHOUT_NFC`, `INTEGRATION_WITHOUT_NFC_ACCESS`, `MRZ_KEY_UNAVAILABLE`, `JPKI_UNAVAILABLE`; consulta [Motivos de omisión](https://docs.didit.me/es/core-technology/nfc-verification/warnings-nfc-verification.md#motivos-de-omisión). El payload de la decisión también incluye un `nfc_skip_reason` a nivel de sesión con la misma taxonomía, que cubre los pasos NFC que se omitieron antes de crear cualquier informe. | `null` |
| `chip_protocol` | string | No | Cómo se lee el chip: `icao` (chip de pasaporte electrónico o eID ICAO 9303) o `jpki` (My Number Card de Japón). Para `jpki`, `portrait_image`, `signature_image`, `chip_data`, `authenticity` y `certificate_summary` son `null`. También se establece en los pasos omitidos. | `"icao"` |
| `jpki` | object | Sí | Lo que demostró una lectura de la My Number Card: `certificate_types`, `chain_valid`, `signature_valid`, `revocation_status` (`good`, `revoked` o `unchecked`), `ca_generation`, `certificate_expires_at`, `certificates[]`, `attributes` (nombre, fecha de nacimiento, sexo y dirección del certificado de firma), `attributes_match_ocr` y `mismatched_attributes`. Nunca incluye los certificados, sus números de serie ni las firmas. `null` para chips ICAO, para pasos omitidos y cuando el paso se cerró sin ninguna lectura de la tarjeta. Consulta [Campos JPKI](https://docs.didit.me/es/core-technology/nfc-verification/report-nfc-verification.md#campos-jpki). | `null` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "status": "Approved",
  "portrait_image": "https://<media-host>/.../nfc_portrait.jpg?signature=...",
  "signature_image": null,
  "chip_data": {
    "dgs": ["DG1", "DG2", "DG11"],
    "surname": "GARCIA LOPEZ",
    "name": "MARIA",
    "country": "ESP",
    "nationality": "ESP",
    "birth_date": "1990-05-12",
    "expiry_date": "2032-05-11",
    "sex": "F",
    "document_type": "P",
    "document_number": "AB1234567",
    "optional_data": "",
    "birth_date_hash": "4",
    "expiry_date_hash": "7",
    "document_number_hash": "3",
    "optional_data_hash": "",
    "final_hash": "8",
    "mrz_string": "P<ESPGARCIA<LOPEZ<<MARIA<<<<<<<<<<<<<<<<<<<<AB1234567ESP9005124F3205117<<<<<<<<<<<<<<08",
    "mrz_type": "TD3",
    "place_of_birth": "MADRID",
    "address": "CALLE MAYOR 1, MADRID"
  },
  "authenticity": { "sod_integrity": true, "dg_integrity": true },
  "certificate_summary": {
    "issuer": "Common Name: CSCA SPAIN, Organization: DIRECCION GENERAL DE LA POLICIA, Country: ES",
    "subject": "Common Name: DS n-eID SPAIN 2, Organizational Unit: PASSPORT, Organization: DIRECCION GENERAL DE LA POLICIA, Country: ES",
    "serial_number": 118120836164494130086420187336801405660,
    "not_valid_before": "2020-11-18 10:21:11",
    "not_valid_after": "2031-02-18 10:21:11",
    "validation": {
      "csca_verified": true,
      "dsc_revoked": false,
      "dsc_expired": false,
      "csca_expired": false
    }
  },
  "node_id": "first_nfc",
  "is_nfc_skipped": false,
  "skip_reason": null,
  "chip_protocol": "icao",
  "jpki": null,
  "warnings": []
}
```

### Prueba de vida

Se devuelve por cada sesión de prueba de vida. Aparece como `liveness_checks[]` en `GET /v3/session/{sessionId}/decision/`. Fuente: `face/serializers/face.py:301-320` (`LivenessV3Serializer`, extiende `LivenessV2Serializer` en `face/serializers/face.py:216-298`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `method` | string (enum) | Sí | `ACTIVE_3D`, `FLASHING` o `PASSIVE` (`LivenessMethodChoices`, `common/config/choices.py:514-517`). El modo pasivo se ejecuta cuando se permiten las sesiones de escritorio y el usuario está en un dispositivo de escritorio. | `"PASSIVE"` |
| `score` | float (0-100) | Sí | Confianza de la prueba de vida, redondeada a 2 decimales. | `92.41` |
| `reference_image` | string (URL) | Sí | URL prefirmada del recorte facial de referencia del usuario. | `"https://<media-host>/.../reference.jpg?..."` |
| `video_url` | string (URL) | Sí | URL prefirmada del video de la prueba de vida (solo en modo activo). | `"https://<media-host>/.../liveness.webm?..."` |
| `age_estimation` | float | Sí | Edad estimada (en años) del rostro más grande de la imagen de referencia. | `34.2` |
| `matches` | array de objetos | No | Coincidencias faciales entre sesiones. Cada elemento: `{ session_id, session_number, similarity_percentage, vendor_data, vendor_user_id, biometric_template_id, verification_date, user_details: { full_name, document_type, document_number }, match_image_url, status, is_blocklisted, is_allowlisted, api_service, source }`. `source` es `session`, `imported`, `list_entry` o `retained_template`. Una coincidencia con una plantilla retenida tiene `vendor_user_id`, `vendor_data` y `biometric_template_id`; sus campos de sesión, imagen, datos de identidad, estado y servicio de API son `null`. | `[]` |
| `face_quality` | float (0-100) | Sí | Puntuación de calidad facial de la prueba de vida pasiva (normalizada a un porcentaje). | `87.50` |
| `face_luminance` | float (0-100) | Sí | Puntuación de luminancia facial de la prueba de vida pasiva (normalizada de 0-255 a un porcentaje). | `54.12` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_liveness"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "status": "Approved",
  "method": "PASSIVE",
  "score": 92.41,
  "reference_image": "https://<media-host>/.../reference.jpg?signature=...",
  "video_url": null,
  "age_estimation": 34.2,
  "matches": [],
  "face_quality": 87.50,
  "face_luminance": 54.12,
  "node_id": "first_liveness",
  "warnings": []
}
```

### Coincidencia facial

Se devuelve por cada comparación de coincidencia facial (normalmente, el rostro del usuario en la prueba de vida frente al retrato del documento). Aparece como `face_matches[]` en `GET /v3/session/{sessionId}/decision/`. Fuente: `face/serializers/face.py:367-389` (`FaceMatchV3Serializer`, extiende `FaceMatchV2Serializer` en `face/serializers/face.py:323-364`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `score` | float (0-100) | Sí | Similitud, redondeada a 2 decimales. Cuando el proveedor solo devuelve un `unmatched_faces[].Confidence`, se convierte en `100 - confidence`. | `97.83` |
| `source_image_session_id` | string (UUID) | Sí | La sesión cuyo retrato almacenado proporcionó la imagen de origen (referencia); se establece en los flujos basados en retrato (autenticación biométrica o un retrato proporcionado al crear la sesión). `null` cuando la referencia es el retrato del documento de la misma sesión. | `null` |
| `source_image` | string (URL) | Sí | URL prefirmada de la imagen de origen (referencia): normalmente el retrato del documento, o el retrato almacenado en los flujos de autenticación biométrica. | `"https://<media-host>/.../source.jpg?..."` |
| `target_image` | string (URL) | Sí | URL prefirmada de la imagen de destino (rostro en vivo) capturada durante la prueba de vida. | `"https://<media-host>/.../target.jpg?..."` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_face_match"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |
| `face_coverage` | object | Sí | Indica si `eyes`, `mouth` y `face` están cubiertos en la imagen capturada. Cada región tiene `covered`, `calibrated` y `visibility_score`; `calibrated: false` indica evidencia en modo sombra sobre la que no actúa ninguna advertencia. Solo lo devuelve `GET /v3/session/{sessionId}/decision/`, nunca aparece en los payloads de webhook. | `{ "eyes": { "covered": false, "calibrated": true, "visibility_score": 0.98 } }` |

```json theme={null}
{
  "status": "Approved",
  "score": 97.83,
  "source_image_session_id": null,
  "source_image": "https://<media-host>/.../source.jpg?signature=...",
  "target_image": "https://<media-host>/.../target.jpg?signature=...",
  "node_id": "first_face_match",
  "warnings": []
}
```

### Búsqueda facial

Lo devuelve la API independiente de Búsqueda facial (`POST /v3/face-search/`). La Búsqueda facial nunca aparece como un array en plural en `/v3/session/{sessionId}/decision/`: cuando se guarda con `save_api_request=true`, la sesión aparece ahí como una entrada `FACE_SEARCH` en `features[]` más un elemento de `liveness_checks[]` que contiene los `matches` almacenados. Fuentes: `apis/serializers/face_search.py:8-79` (`FaceSearchResponseSerializer`, que envuelve `FaceSearchDetailsSerializer`); los diccionarios de coincidencias se construyen en `face/utils/utils.py:869-884`.

Respuesta de nivel superior:

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `request_id` | string (UUID) | No | El id de la sesión guardada cuando `save_api_request=true` (se puede usar con `GET /v3/session/{sessionId}/decision/`); en caso contrario, un UUID de correlación transitorio. | `"4a1c2c4e-8b1b-4d6a-91b5-ee9a1f3a2c7f"` |
| `face_search` | objeto | No | El payload con los detalles de la búsqueda; consulta los campos más abajo. | — |
| `vendor_data` | string | Sí | El `vendor_data` de la solicitud, devuelto tal cual. | `null` |
| `metadata` | objeto | Sí | El `metadata` de la solicitud, devuelto tal cual. | `null` |
| `created_at` | string (ISO 8601) | No | Marca de tiempo de la solicitud en el servidor. | `"2026-06-12T01:04:42.763237+00:00"` |

Objeto `face_search`:

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | `Declined` solo cuando se ha disparado una advertencia `FACE_IN_BLOCKLIST` o `POSSIBLE_FACE_IN_BLOCKLIST`; `Approved` en cualquier otro caso: las coincidencias duplicadas por sí solas nunca provocan un rechazo (`apis/views/face_search.py:242-248`). | `"Approved"` |
| `total_matches` | entero | No | Número de coincidencias devueltas en `matches[]` (0–5). | `1` |
| `matches` | array de [objetos de coincidencia de búsqueda facial](#objeto-de-coincidencia-de-búsqueda-facial) | No | Hasta 5 coincidencias por encima del umbral mínimo de similitud, ordenadas por similitud descendente (las entradas de la lista de bloqueo van primero con `search_type=blocklisted_or_approved`). | `[…]` |
| `user_image` | objeto | No | Resultado de la detección en la imagen enviada: `{ entities: [{ bbox, confidence }], best_angle }`, con una entidad por cada rostro detectado. | `{ "entities": [{ "bbox": [40, 40, 120, 120], "confidence": 0.73 }], "best_angle": 0 }` |
| `warnings` | array de objetos | No | Estructura de advertencia reducida para esta API independiente, sin `node_id`. El contrato del serializador declara `{ risk, additional_data, log_type, short_description, long_description }` (`apis/serializers/face_search.py:49-54`); el payload en tiempo de ejecución también incluye `feature`, siempre `"LIVENESS"` (`apis/views/face_search.py:332-341`). | `[]` |

#### Objeto de coincidencia de búsqueda facial

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `session_id` | string (UUID) | Sí | La sesión de verificación coincidente. `null` cuando `source` es `imported`, `list_entry` o `retained_template`. | `"a3f2a6f1-…"` |
| `session_number` | entero | Sí | Número de la sesión coincidente tal como se muestra en la consola; `null` para coincidencias que no proceden de una sesión. | `1024` |
| `similarity_percentage` | float (0-100) | No | Similitud entre el rostro enviado y el rostro coincidente. | `96.42` |
| `source` | string (enum) | No | Origen desde el que se registró el rostro coincidente: `session` (sesión de verificación o llamada independiente guardada), `imported` (rostro subido directamente al perfil de usuario), `list_entry` (rostro asociado a una lista), `retained_template` ([plantilla biométrica](https://docs.didit.me/es/management-api/biometric-templates/overview.md) sin imagen conservada después de eliminarse la sesión de origen). | `"session"` |
| `vendor_data` | string | Sí | El `vendor_data` de la sesión coincidente, o el del User vinculado en las coincidencias `imported` y `retained_template`. | `"user-12345"` |
| `vendor_user_id` | string (UUID) | Sí | El User vinculado. `null` para coincidencias `list_entry` y para sesiones sin User. | `"2f7c1a9e-…"` |
| `biometric_template_id` | string (UUID) | Sí | La plantilla conservada que ha coincidido. Solo se informa en coincidencias `retained_template`; úsala con `GET`/`DELETE /v3/biometric-templates/{id}/`. | `null` |
| `verification_date` | string (ISO 8601) | Sí | Cuándo se capturó el rostro coincidente o cuándo se conservó una `retained_template`; `null` para coincidencias `list_entry`. | `"2024-11-04T09:14:02Z"` |
| `user_details` | objeto | Sí | `{ full_name, document_type, document_number }` procedentes de la verificación de documento de la sesión coincidente; en las coincidencias `imported` solo se informa `full_name`; `null` cuando no hay datos de identidad y siempre `null` en las coincidencias `retained_template`. | `{ "full_name": "María García López", "document_type": "Passport", "document_number": "AB1234567" }` |
| `match_image_url` | string (URL) | Sí | Rostro de referencia del usuario coincidente: URL prefirmada cuando `save_api_request=true` y ruta de almacenamiento sin procesar en caso contrario. Siempre `null` en las coincidencias `retained_template`, que no contienen imagen. | `"https://<media-host>/.../matched.jpg?..."` |
| `status` | string | Sí | El estado de verificación de la sesión coincidente (consulta [Enum de estado](#referencia-de-los-valores-de-estado)); `null` para coincidencias que no proceden de una sesión. | `"Approved"` |
| `is_blocklisted` | booleano | No | Indica si el rostro coincidente está en tu lista de bloqueo de rostros. Siempre `false` en las coincidencias `retained_template`; un rostro en la lista de bloqueo se informa por separado como coincidencia `list_entry`. | `false` |
| `is_allowlisted` | booleano | No | Indica si el rostro coincidente está en alguna de tus listas de permitidos. | `false` |
| `api_service` | string (enum) | Sí | Tipo de API independiente, en mayúsculas, de la sesión coincidente (p. ej., `PASSIVE_LIVENESS`, `FACE_MATCH`); `null` para sesiones de flujo y coincidencias que no proceden de una sesión. | `null` |

```json theme={null}
{
  "request_id": "4a1c2c4e-8b1b-4d6a-91b5-ee9a1f3a2c7f",
  "face_search": {
    "status": "Approved",
    "total_matches": 1,
    "matches": [
      {
        "session_id": "a3f2a6f1-1c1c-4eec-8b69-1c1c2f3a2c7f",
        "session_number": 1024,
        "similarity_percentage": 96.42,
        "source": "session",
        "vendor_data": "user-12345",
        "verification_date": "2024-11-04T09:14:02Z",
        "user_details": {
          "full_name": "María García López",
          "document_type": "Passport",
          "document_number": "AB1234567"
        },
        "match_image_url": "https://<media-host>/.../matched.jpg?signature=...",
        "status": "Approved",
        "is_blocklisted": false,
        "is_allowlisted": false,
        "api_service": null
      }
    ],
    "user_image": {
      "entities": [
        {
          "bbox": [40, 40, 120, 120],
          "confidence": 0.732973
        }
      ],
      "best_angle": 0
    },
    "warnings": []
  },
  "vendor_data": null,
  "metadata": null,
  "created_at": "2026-06-12T01:04:42.763237+00:00"
}
```

### Análisis AML

Se devuelve por cada entidad analizada. Aparece como `aml_screenings[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones KYC como KYB. Fuente: `aml/serializers/aml.py:63-85` (`AMLV3Serializer`, que extiende `AMLV2Serializer` en `aml/serializers/aml.py:28-60`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `total_hits` | entero | No | Número de resultados del análisis (siempre presente; valor predeterminado `0`). | `2` |
| `entity_type` | string (enum) | Sí | `person` o `company` (`EntityTypeChoices`, `common/config/choices.py:675-677`). | `"person"` |
| `hits` | array de objetos | No | Una entrada por resultado. Campos principales: `id`, `caption`, `match` (bool), `target` (bool \| null: indica si la entidad es el objetivo directo del listado), `match_score` (float 0-100, confianza en la identidad), `risk_score` (float 0-100, riesgo de la entidad), `score` (float 0-1 obsoleto), `datasets[]` (p. ej., `PEP`, `PEP Level 1`-`4`, `Sanctions`, `Adverse Media`, `Warnings and Regulatory Enforcement`, `Fitness and Probity`), `properties` (nombres, alias, fechas de nacimiento, …), `features`, `url`, `first_seen`, `last_seen`, `rca_name`, `risk_view`, `score_breakdown`, `pep_matches`, `sanction_matches`, `warning_matches`, `adverse_media_matches`, `adverse_media_details`, `linked_entities`, `additional_information` y `review_status` (`Unreviewed`, `Confirmed Match`, `False Positive`, `Inconclusive`; se puede editar mediante el endpoint de actualización del estado de resultados AML, `AMLHitStatusChoices`). | `[…]` |
| `score` | float (0-100) | Sí | Puntuación global del análisis: la `risk_score` más alta entre los resultados no marcados como `False Positive` (`aml/services/aml.py:832-842`); `0` cuando todos los resultados son falsos positivos. `null` hasta que se calcula. | `42.7` |
| `screened_data` | object | Sí | Instantánea de los datos enviados al análisis: `full_name`, `nationality`, `date_of_birth`, `document_number`. | `{ "full_name": "María García López", "date_of_birth": "1990-05-12" }` |
| `is_ongoing_monitoring_enabled` | boolean | No | Indica si la entidad está suscrita a los nuevos análisis de la monitorización continua. | `false` |
| `next_ongoing_monitoring_bill_date` | string (YYYY-MM-DD) | Sí | Se calcula como `last_aml_bill_date + 365 days` cuando la monitorización continua está activada. Es una fecha relativa a **la facturación**, no una fecha de análisis. | `null` |
| `last_ongoing_screening_at` | string (ISO 8601) | Sí | Momento en que la monitorización continua completó por última vez un nuevo análisis de este registro, haya cambiado o no el resultado. `null` si nunca se ha vuelto a analizar; nunca se rellena con fechas anteriores. | `"2026-09-12T04:03:11Z"` |
| `last_ongoing_screening_datasets_updated_at` | string (ISO 8601) | Sí | Actualización más reciente de los conjuntos de datos AML que el proveedor indicó para ese análisis. `null` si no se indicó ninguna fecha de conjunto de datos; nunca se estima. | `null` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_aml"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "status": "In Review",
  "total_hits": 1,
  "entity_type": "person",
  "hits": [
    {
      "id": "Q7XW3-aml-hit-1",
      "caption": "Maria Garcia Lopez",
      "match": true,
      "target": true,
      "match_score": 86.4,
      "risk_score": 42.7,
      "datasets": ["PEP Level 2"],
      "properties": {
        "name": ["María García López", "M. García"],
        "alias": ["Maria Garcia"],
        "birthDate": ["1990-05-12"]
      },
      "url": "https://example.org/registry/entities/Q7XW3",
      "first_seen": "2023-11-02T00:00:00Z",
      "last_seen": "2026-05-01T00:00:00Z",
      "review_status": "Unreviewed"
    }
  ],
  "score": 42.7,
  "screened_data": {
    "full_name": "María García López",
    "date_of_birth": "1990-05-12",
    "nationality": "ES",
    "document_number": "AB1234567"
  },
  "is_ongoing_monitoring_enabled": false,
  "next_ongoing_monitoring_bill_date": null,
  "last_ongoing_screening_at": null,
  "last_ongoing_screening_datasets_updated_at": null,
  "node_id": "first_aml",
  "warnings": []
}
```

### Análisis de IP

Se devuelve por cada ubicación de red capturada. Aparece como `ip_analyses[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones KYC como KYB. Fuente: `kyc/serializers/location.py:196-243` (`IPAnalysisSerializerV3`).

| Campo | Tipo | Nulable | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_ip_analysis"` |
| `device_brand` | string | Sí | Marca del dispositivo obtenida del user agent. | `"Apple"` |
| `device_model` | string | Sí | Modelo del dispositivo. | `"iPhone"` |
| `browser_family` | string | Sí | Familia del navegador. | `"Mobile Safari"` |
| `os_family` | string | Sí | Familia del sistema operativo. | `"iOS"` |
| `platform` | string | Sí | Plataforma general (`mobile`, `desktop`, `tablet`). | `"mobile"` |
| `device_fingerprint` | string | Sí | Hash de huella estable por dispositivo. | `"f2a3…"` |
| `ip_country` | string | Sí | Nombre del país obtenido a partir de la IP. | `"Spain"` |
| `ip_country_code` | string (ISO 3166-1 alpha-2) | Sí | Código de país obtenido a partir de la IP. | `"ES"` |
| `ip_state` | string | Sí | Región o estado obtenido a partir de la IP. | `"Comunidad de Madrid"` |
| `ip_city` | string | Sí | Ciudad obtenida a partir de la IP. | `"Madrid"` |
| `latitude` | float | Sí | Latitud obtenida a partir de la IP. | `40.4168` |
| `longitude` | float | Sí | Longitud obtenida a partir de la IP. | `-3.7038` |
| `ip_address` | string | Sí | La dirección IP capturada. | `"203.0.113.42"` |
| `isp` | string | Sí | Nombre del ISP. | `"Telefonica de Espana"` |
| `organization` | string | Sí | Nombre de la organización (a menudo igual al ISP). | `"Telefonica de Espana"` |
| `is_vpn_or_tor` | boolean | Sí | `true` cuando la IP pertenece a una VPN, un proxy o un nodo de salida de Tor. | `false` |
| `is_data_center` | boolean | Sí | `true` cuando la IP pertenece a un ASN conocido de hosting o de centro de datos. | `false` |
| `time_zone` | string | Sí | Nombre de la zona horaria IANA. | `"Europe/Madrid"` |
| `time_zone_offset` | string | Sí | Desfase respecto a UTC. | `"+02:00"` |
| `ip` | object | No | `{ location, distance_from_id_document, distance_from_poa_document }`. `location = { latitude, longitude }`. Distancias en km, `null` cuando falta alguno de los dos extremos. | `{ "location": { "latitude": 40.4168, "longitude": -3.7038 }, "distance_from_id_document": 3.4, "distance_from_poa_document": 1.1 }` |
| `id_document` | object | No | `{ location, distance_from_ip, distance_from_poa_document }`. Ubicación del documento de identidad obtenida a partir de `issuing_state` y de la dirección extraída. | `{ "location": { "latitude": 40.4165, "longitude": -3.7026 }, "distance_from_ip": 3.4, "distance_from_poa_document": 4.0 }` |
| `poa_document` | object | No | `{ location, distance_from_ip, distance_from_id_document }`. Dirección de la prueba de domicilio geocodificada. | `{ "location": { "latitude": 40.4170, "longitude": -3.7040 }, "distance_from_ip": 1.1, "distance_from_id_document": 4.0 }` |
| `matches` | array de objetos | No | Coincidencias de IP o dispositivo entre sesiones. Cada elemento: `{ session_id, session_number, vendor_data, verification_date, match_type, match_source, matched_value, status, is_blocklisted, api_service, source, device_info, location_info, confidence, match_mode }`. `match_type` es `ip_address` o `device_fingerprint`; `match_source` es `ip_address`, `persistent_id`, `legacy_fp` o `recovered_high` (las coincidencias recuperadas también incluyen `recovery_similarity`, `tls_ja4_corroborated`, `recovery_gate_reason`). Limitado a 5 coincidencias de IP y 5 de dispositivo. | `[]` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |
| `browser_version`, `os_version` | string | Sí | Versiones del navegador y del sistema operativo obtenidas del user agent. | `"17.4"` |
| `user_agent`, `accept_language` | string | Sí | La cadena del user agent y el encabezado `Accept-Language` que envió el navegador. | `"en-US,en;q=0.9"` |
| `session_identifier`, `session_age_ms` | string, integer | Sí | La sesión de navegación en la que se ejecutó el paso y su antigüedad en milisegundos. | `48210` |
| `coords_accuracy` | float | Sí | Radio de precisión, en metros, de las coordenadas que indicó el dispositivo. | `35.0` |
| `raw_device_data` | object | Sí | Señales sin procesar del dispositivo recopiladas para el paso. | `{}` |

```json theme={null}
{
  "status": "Approved",
  "node_id": "first_ip_analysis",
  "device_brand": "Apple",
  "device_model": "iPhone",
  "browser_family": "Mobile Safari",
  "os_family": "iOS",
  "platform": "mobile",
  "device_fingerprint": "f2a3c1de8b994a3f9e4cdf3a02b1a7c9",
  "ip_country": "Spain",
  "ip_country_code": "ES",
  "ip_state": "Comunidad de Madrid",
  "ip_city": "Madrid",
  "latitude": 40.4168,
  "longitude": -3.7038,
  "ip_address": "203.0.113.42",
  "isp": "Telefonica de Espana",
  "organization": "Telefonica de Espana",
  "is_vpn_or_tor": false,
  "is_data_center": false,
  "time_zone": "Europe/Madrid",
  "time_zone_offset": "+02:00",
  "ip": {
    "location": { "latitude": 40.4168, "longitude": -3.7038 },
    "distance_from_id_document": 3.4,
    "distance_from_poa_document": 1.1
  },
  "id_document": {
    "location": { "latitude": 40.4165, "longitude": -3.7026 },
    "distance_from_ip": 3.4,
    "distance_from_poa_document": 4.0
  },
  "poa_document": {
    "location": { "latitude": 40.4170, "longitude": -3.7040 },
    "distance_from_ip": 1.1,
    "distance_from_id_document": 4.0
  },
  "matches": [],
  "warnings": []
}
```

### Verificación de ubicación

Se devuelve por cada paso de [Verificación de ubicación](https://docs.didit.me/es/core-technology/location-verification/overview.md). Aparece como `geolocation_checks[]` en `GET /v3/session/{sessionId}/decision/`: un elemento por paso, con su intento aceptado. `geolocation_attempts[]` enumera todos los intentos de todos los pasos, del más antiguo al más reciente. Ambos son `null` en un flujo sin este paso. Fuente: `GeolocationDecisionSerializer`.

| Campo | Tipo | Nulable | Descripción | Ejemplo |
| - | - | - | - | - |
| `node_id` | string | Sí | Nodo del flujo que generó el resultado. | `"geolocation_1"` |
| `status` | string | No | Consulta [enum de estado](#referencia-de-los-valores-de-estado). | `"Declined"` |
| `outcome` | string | Sí | Qué ocurrió en el intento: `verified`, `low_accuracy`, `accuracy_undetermined`, `stale`, `approximate`, `denied`, `restricted`, `unavailable`, `timeout`, `mock_detected`, `outside_geofence`, `in_blocked_area`, `anonymizer_detected`, `skipped`, `replay_rejected` o `unsupported_client`. | `"outside_geofence"` |
| `permission` | string | Sí | Qué concedió el sistema: `granted_precise`, `granted_approximate`, `denied`, `restricted`, `unavailable`, `timeout`, `dismissed` o `not_requested`. | `"granted_precise"` |
| `latitude`, `longitude` | float | Sí | Posición WGS84. `null` cuando no hay posición. | `48.8566` |
| `accuracy_m` | float | Sí | Radio de incertidumbre en metros. | `35.0` |
| `accuracy_confidence` | string | Sí | `p95`, `p68` o `unspecified`. | `"p95"` |
| `measured_at`, `age_seconds` | datetime, integer | Sí | Cuándo obtuvo el dispositivo la posición y los segundos que pasaron hasta que Didit la recibió. | `2` |
| `source`, `platform`, `sdk_version` | string | Sí | De dónde procede la posición, el cliente que la generó y su versión del SDK. | `"browser"` |
| `is_mock`, `produced_by_accessory` | boolean | Sí | Indicios de suplantación que informa la plataforma. `null` significa que la plataforma no los informa. | `null` |
| `integrity` | string | No | `attested`, `not_attested`, `failed`, `unsupported` (web) o `not_determined`. | `"unsupported"` |
| `country_code`, `region_code`, `city` | string | Sí | El lugar al que corresponde la posición. | `"FR"` |
| `geofence`, `inside_geofence`, `geofence_basis`, `inside_areas`, `blocked_areas` | object, boolean, string, arrays | Sí | El resultado por país y por zona. | `{ "enabled": true, "result": "outside" }` |
| `position_source`, `anonymizers` | string, object | Sí | De dónde toma el paso la posición, y las señales de VPN, proxy, Tor, suplantación y emulador. | `"device_and_ip"` |
| `ip_distance_km`, `ip_distance_uncertainty_km`, `ip_consistent`, `document_distance_km`, `travel_excused`, `consecutive_mismatches` | number, boolean, integer | Sí | Las comparaciones con la ubicación de la IP y con la dirección registrada. | `12.4` |
| `attempts` | integer | No | El número del intento dentro del paso. | `3` |
| `consent` | object | Sí | `accepted_at`, `version` y `locale` del aviso que aceptó la persona. | |
| `warnings` | array de [objetos de advertencia](#objeto-de-advertencia) | No | Las advertencias `LOCATION_*` del paso. No aparece en `geolocation_attempts[]`, que añade `received_at` y `created_at`. | `[]` |

Todos los campos y ejemplos están en el [informe de verificación de ubicación](https://docs.didit.me/es/core-technology/location-verification/report-location-verification.md).

### Prueba de domicilio

Se devuelve por cada documento de domicilio enviado. Aparece como `poa_verifications[]` en `GET /v3/session/{sessionId}/decision/`. Fuente: `poa/serializers/poa.py:212-227` (`POAV3Serializer`, que extiende `POAV2Serializer` en `poa/serializers/poa.py:173-209`).

| Campo | Tipo | Admite nulo | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `issuing_state` | string (ISO 3166-1 alpha-3) | Sí | Código de país del emisor del documento. | `"ESP"` |
| `document_type` | string | No | Tipo general de `PoaDocumentTypeChoices` (`common/config/choices.py:868-873`): `UTILITY_BILL`, `BANK_STATEMENT`, `GOVERNMENT_ISSUED_DOCUMENT`, `OTHER_POA_DOCUMENT`. Si no se determina, vale `UNKNOWN`; nunca es `null`. | `"UTILITY_BILL"` |
| `document_subtype` | string | No | Código de subtipo de `PoaDocumentSubtypeChoices` (p. ej., `ELECTRICITY_BILL`, `WATER_BILL`, `ACCOUNT_STATEMENT`). Si no se determina, vale `UNKNOWN`; nunca es `null`. | `"ELECTRICITY_BILL"` |
| `issuer` | string | Sí | Nombre de la entidad emisora. | `"Iberdrola"` |
| `issue_date` | string (YYYY-MM-DD) | Sí | Fecha de emisión del documento. | `"2026-04-15"` |
| `expiration_date` | string (YYYY-MM-DD) | Sí | Fecha de caducidad impresa en el documento, si la tiene. | `null` |
| `poa_address` | string | Sí | Dirección extraída por OCR, sin procesar. | `"Calle Mayor 1, 28001 Madrid"` |
| `poa_formatted_address` | string | Sí | Dirección geocodificada y formateada. | `"Calle Mayor 1, 28001 Madrid, Spain"` |
| `poa_parsed_address` | object | Sí | Dirección estructurada (`street_1`, `street_2`, `city`, `region`, `postal_code`, `country` (alpha-2), `address_type`, `document_location`, …). | `{ "street_1": "Calle Mayor 1", "city": "Madrid", "postal_code": "28001" }` |
| `document_file` | string (URL) | Sí | URL prefirmada del documento subido. | `"https://<media-host>/.../poa.pdf?..."` |
| `document_language` | string | Sí | Idioma detectado del documento (ISO 639-1). | `"es"` |
| `document_metadata` | object | Sí | Metadatos filtrados: `file_size`, `content_type`, `creation_date`, `modified_date`, `creator`, `producer`, `software`, `encryption`, `is_signed`, `is_tampered`, `signature_info`, `exif_original_date`, `exif_digitized_date`, `processed_by_known_editor`, `has_different_creation_mod_date`, `overlay_manipulation`. | `{ "file_size": 184221, "content_type": "application/pdf", "is_tampered": false }` |
| `extra_fields` | object | No | Campos de cuenta bancaria (`bank_account_number`, `bank_iban`, `bank_sort_code`, `bank_routing_number`, `bank_swift_bic`, `bank_branch_name`, `bank_branch_address`), `document_phone_number`, `additional_names` y cualquier clave personalizada guardada en el registro. | `{ "bank_iban": null, "additional_names": [] }` |
| `name_on_document` | string | Sí | Nombre tal como aparece en el documento de domicilio. | `"María García López"` |
| `expected_details_address` | string | Sí | Dirección que el cliente escribió durante el registro (literal). | `"Calle Mayor 1, Madrid"` |
| `expected_details_formatted_address` | string | Sí | Dirección esperada geocodificada. | `"Calle Mayor 1, 28001 Madrid, Spain"` |
| `expected_details_parsed_address` | object | Sí | Dirección esperada estructurada. | `{ "city": "Madrid", "postal_code": "28001" }` |
| `name_match_score_expected_details` | float (0-100) | Sí | Coincidencia aproximada entre `name_on_document` y el nombre proporcionado al crear la sesión. | `94.0` |
| `name_match_score_id_verification` | float (0-100) | Sí | Coincidencia aproximada entre `name_on_document` y el `full_name` del documento de identidad verificado. | `100.0` |
| `extra_files` | array de strings (URL) | No | URL prefirmadas de archivos adicionales subidos. | `[]` |
| `detected_codes` | array de objetos | No | Códigos QR y códigos de barras detectados en todas las páginas procesadas del documento: `type`, `page_number` (empieza en 1), `position` (polígono), `x`/`y`/`width`/`height` (cuadro delimitador), `page_width`/`page_height`, `raw_payload` (base64), `parsed_payload` (valor decodificado, `null` cuando se localizó un código pero no se pudo decodificar). Array vacío cuando la detección no encuentra nada. | `[{ "type": "QR_CODE", "page_number": 1, "parsed_payload": "https://issuer.example/inv/9981" }]` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_poa"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "status": "Approved",
  "issuing_state": "ESP",
  "document_type": "UTILITY_BILL",
  "document_subtype": "ELECTRICITY_BILL",
  "issuer": "Iberdrola",
  "issue_date": "2026-04-15",
  "expiration_date": null,
  "poa_address": "Calle Mayor 1, 28001 Madrid",
  "poa_formatted_address": "Calle Mayor 1, 28001 Madrid, Spain",
  "poa_parsed_address": { "street_1": "Calle Mayor 1", "city": "Madrid", "postal_code": "28001", "country": "ES" },
  "document_file": "https://<media-host>/.../poa.pdf?signature=...",
  "document_language": "es",
  "document_metadata": {
    "file_size": 184221,
    "content_type": "application/pdf",
    "creation_date": "2026-04-15T08:11:32Z",
    "modified_date": "2026-04-15T08:11:32Z",
    "creator": "Iberdrola Billing",
    "producer": "Adobe PDF Library 15.0",
    "software": null,
    "encryption": null,
    "is_signed": true,
    "is_tampered": false,
    "signature_info": { "signer_name": "Iberdrola Clientes", "date": "2026-04-15T08:11:32Z" },
    "exif_original_date": null,
    "exif_digitized_date": null,
    "processed_by_known_editor": false,
    "has_different_creation_mod_date": false,
    "overlay_manipulation": null
  },
  "extra_fields": {
    "bank_account_number": null,
    "bank_iban": null,
    "bank_sort_code": null,
    "bank_routing_number": null,
    "bank_swift_bic": null,
    "bank_branch_name": null,
    "bank_branch_address": null,
    "document_phone_number": null,
    "additional_names": []
  },
  "name_on_document": "María García López",
  "expected_details_address": "Calle Mayor 1, Madrid",
  "expected_details_formatted_address": "Calle Mayor 1, 28001 Madrid, Spain",
  "expected_details_parsed_address": { "city": "Madrid", "postal_code": "28001", "country": "ES" },
  "name_match_score_expected_details": 94.0,
  "name_match_score_id_verification": 100.0,
  "extra_files": [],
  "detected_codes": [
    {
      "type": "QR_CODE",
      "page_number": 1,
      "position": [[820, 1120], [1002, 1120], [1002, 1302], [820, 1302]],
      "x": 820,
      "y": 1120,
      "width": 182,
      "height": 182,
      "page_width": 1190,
      "page_height": 1684,
      "raw_payload": "aHR0cHM6Ly9pYmVyZHJvbGEuZXMvZmFjdHVyYS85OTgx",
      "parsed_payload": "https://iberdrola.es/factura/9981"
    },
    {
      "type": "CODE_128",
      "page_number": 1,
      "position": [[112, 1480], [560, 1480], [560, 1540], [112, 1540]],
      "x": 112,
      "y": 1480,
      "width": 448,
      "height": 60,
      "page_width": 1190,
      "page_height": 1684,
      "raw_payload": "MDA5OTgxMDAwNDI=",
      "parsed_payload": "0099810042"
    }
  ],
  "node_id": "first_poa",
  "warnings": []
}
```

### Verificación de teléfono

Se devuelve por cada intento de verificación de teléfono. Aparece como `phone_verifications[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones de KYC como de KYB. Fuente: `phone/serializers/phone.py:251-266` (`PhoneV3Serializer`, extiende `PhoneV2Serializer` en `phone/serializers/phone.py:103-248`).

| Campo | Tipo | Nulable | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `phone_number_prefix` | string | No | Prefijo de país E.164 (con `+`). | `"+34"` |
| `phone_number` | string | No | Número del abonado sin el prefijo. | `"612345678"` |
| `full_number` | string | No | El número E.164 completo (`phone_number_prefix + phone_number`). | `"+34612345678"` |
| `country_code` | string (ISO 3166-1 alpha-2) | Sí | País del número. | `"ES"` |
| `country_name` | string | Sí | Nombre del país localizado. | `"Spain"` |
| `carrier` | objeto | No | `{ name, type }`, donde `type` es un valor de `LineTypeChoices` (`common/config/choices.py:648-667`): `mobile`, `fixed_line`, `voip`, `isp`, `vpn`, `toll_free`, `premium_rate`, `satellite`, `pager`, `payphone`, `voice_mail`, `unknown` y otras clases de línea. | `{ "name": "Movistar", "type": "mobile" }` |
| `is_disposable` | booleano | No | `true` cuando el operador marca el número como temporal o desechable. | `false` |
| `is_virtual` | booleano | No | `true` cuando `carrier.type` es uno de `voip`, `isp`, `vpn`. | `false` |
| `verification_method` | string | No | Canal usado para entregar el OTP (`whatsapp`, `sms`, …). Se lee del `actual_channel` del último intento de envío (si no existe, se usa el `channel` solicitado y, en su defecto, `sms`). | `"whatsapp"` |
| `verification_attempts` | entero | No | Total de intentos de envío del OTP (envío inicial más reenvíos). | `1` |
| `verified_at` | string (ISO 8601) | Sí | Marca de tiempo en la que se introdujo correctamente el OTP. | `"2026-05-17T10:14:02Z"` |
| `lifecycle` | array de objetos | No | Eventos en orden cronológico: intentos de envío, callbacks de entrega, comprobaciones del código y el evento de estado final. Cada evento es `{ type, timestamp, details, fee }`. Los tipos de evento provienen de `PhoneEventChoices`. | `[…]` |
| `matches` | array de objetos | No | Coincidencias del número de teléfono entre sesiones. Cada elemento: `{ session_id, session_number, vendor_data, verification_date, phone_number, status, is_blocklisted, api_service, source }`. `source` es `session` o `list_entry`. | `[]` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_phone"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |
| `phone_intelligence` | objeto | Sí | Señales de inteligencia del teléfono. Solo está presente cuando el complemento de inteligencia se ejecutó para el número. | |
| `phone_social` | objeto | Sí | Huella social del número. Solo está presente cuando se ejecutó el complemento de huella social. | |

```json theme={null}
{
  "status": "Approved",
  "phone_number_prefix": "+34",
  "phone_number": "612345678",
  "full_number": "+34612345678",
  "country_code": "ES",
  "country_name": "Spain",
  "carrier": { "name": "Movistar", "type": "mobile" },
  "is_disposable": false,
  "is_virtual": false,
  "verification_method": "whatsapp",
  "verification_attempts": 1,
  "verified_at": "2026-05-17T10:14:02Z",
  "lifecycle": [
    {
      "type": "PHONE_VERIFICATION_MESSAGE_SENT",
      "timestamp": "2026-05-17T10:13:51Z",
      "details": { "status": "Success", "reason": null, "channel": "whatsapp", "actual_channel": "whatsapp" },
      "fee": 0.02
    },
    {
      "type": "PHONE_DELIVERY_DELIVERED",
      "timestamp": "2026-05-17T10:13:52Z",
      "details": { "channel": "whatsapp", "status": "delivered" },
      "fee": 0
    },
    {
      "type": "VALID_CODE_ENTERED",
      "timestamp": "2026-05-17T10:14:02Z",
      "details": { "code_tried": "482917", "status": "Approved" },
      "fee": 0
    },
    {
      "type": "PHONE_VERIFICATION_APPROVED",
      "timestamp": "2026-05-17T10:14:02Z",
      "details": null,
      "fee": 0
    }
  ],
  "matches": [],
  "node_id": "first_phone",
  "warnings": []
}
```

### Verificación de correo electrónico

Se devuelve por cada intento de verificación de correo electrónico. Aparece como `email_verifications[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones de KYC como de KYB. Fuente: `email_verification/serializers/email.py:149-164` (`EmailV3Serializer`, extiende `EmailV2Serializer` en `email_verification/serializers/email.py:38-146`).

| Campo | Tipo | Nulable | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `email` | string | No | La dirección de correo electrónico enviada. | `"maria.garcia@example.com"` |
| `is_breached` | booleano | No | `true` cuando el correo aparece en una filtración de datos conocida. | `false` |
| `breaches` | array de objetos | No | Detalle de cada filtración cuando `is_breached` es `true`: `{ name, domain, logo_path, breach_date, description, is_verified, data_classes, breach_emails_count }`. | `[]` |
| `is_disposable` | booleano | No | `true` cuando el correo pertenece a un proveedor de correo desechable. | `false` |
| `is_undeliverable` | booleano | No | `true` cuando la comprobación de entrega SMTP indica que el buzón no acepta correo. | `false` |
| `verification_attempts` | entero | No | Total de intentos de comprobación del OTP. | `1` |
| `verified_at` | string (ISO 8601) | Sí | Marca de tiempo en la que se introdujo correctamente el OTP. | `"2026-05-17T10:15:22Z"` |
| `lifecycle` | array de objetos | No | Eventos en orden cronológico: intentos de envío, comprobaciones del código y el evento de estado final. Cada evento es `{ type, timestamp, details, fee }`. Los tipos de evento provienen de `EmailEventChoices`. | `[…]` |
| `matches` | array de objetos | No | Coincidencias del correo electrónico entre sesiones. Cada elemento: `{ session_id, session_number, vendor_data, verification_date, email, status, is_blocklisted, api_service, source }`. `source` es `session` o `list_entry`. | `[]` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_email"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |
| `email_intelligence` | objeto | Sí | Señales de inteligencia del correo electrónico. Solo está presente cuando el complemento de inteligencia se ejecutó para la dirección. | |
| `email_social` | objeto | Sí | Huella social de la dirección. Solo está presente cuando se ejecutó el complemento de huella social. | |

```json theme={null}
{
  "status": "Approved",
  "email": "maria.garcia@example.com",
  "is_breached": false,
  "breaches": [],
  "is_disposable": false,
  "is_undeliverable": false,
  "verification_attempts": 1,
  "verified_at": "2026-05-17T10:15:22Z",
  "lifecycle": [
    {
      "type": "EMAIL_VERIFICATION_MESSAGE_SENT",
      "timestamp": "2026-05-17T10:15:11Z",
      "details": { "status": "Success", "reason": null },
      "fee": 0.02
    },
    {
      "type": "VALID_CODE_ENTERED",
      "timestamp": "2026-05-17T10:15:22Z",
      "details": { "code_tried": "739204", "status": "Approved" },
      "fee": 0
    },
    {
      "type": "EMAIL_VERIFICATION_APPROVED",
      "timestamp": "2026-05-17T10:15:22Z",
      "details": null,
      "fee": 0
    }
  ],
  "matches": [],
  "node_id": "first_email",
  "warnings": []
}
```

### Validación de base de datos

Se devuelve por cada consulta a base de datos realizada con los datos enviados por el usuario. Aparece como `database_validations[]` en `GET /v3/session/{sessionId}/decision/`. Fuente: `database_validation/serializers/database_validation.py:21-142` (`DatabaseValidationV3Serializer`, extiende `DatabaseValidationV2Serializer`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `issuing_state` | string (ISO 3166-1 alpha-3) | Sí | País cuyo registro se consultó. | `"ESP"` |
| `validation_type` | string (enum) | No | Cómo se corroboró el resultado: `one_by_one` (resultado de un único servicio), `two_by_two` (dos o más servicios distintos obtuvieron de forma independiente una coincidencia total del número de identificación) o `not_enabled` (se omitió el validador o ningún proveedor respondió; un `no_match` definitivo sigue dando `one_by_one`). Nunca es `null`. Origen: `DatabaseValidationChoices` (`common/config/choices.py:1097-1100`). | `"one_by_one"` |
| `screened_data` | object | No | Los datos enviados al registro. Los campos de archivo (`selfie`, `cnh_qr_code_image`, `document_image`) se devuelven con URL prefirmadas en el momento de la lectura. | `{ "document_number": "99999999R", "date_of_birth": "1990-05-12" }` |
| `validations` | array of objects | No | Una entrada por cada servicio del catálogo que produjo una coincidencia. Cada entrada puede incluir `service_id`, `service_name`, `validation` (objeto con el veredicto del proveedor), `outcome_code`, `outcome_detail` y `source_data` (perfil depurado del ciudadano: `full_name`, `gender`, `date_of_birth`, `photo` (URL prefirmada), `signature` (URL prefirmada), …). | `[…]` |
| `errors` | array of objects | Sí | Errores por servicio cuando falló una consulta; la clave se omite por completo cuando está vacía. Cada entrada es el objeto de error del servicio de origen más el `service_id` que lo produjo. | `[]` |
| `match_type` | string (enum) | Sí | Veredicto de coincidencia agregado de los servicios consultados: `full_match`, `partial_match` o `no_match` (`DatabaseValidationMatchTypeChoices`, `common/config/choices.py:1103-1106`). Es `null` hasta que se evalúa. | `"full_match"` |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_db_validation"` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "issuing_state": "ESP",
  "validation_type": "one_by_one",
  "screened_data": {
    "document_number": "99999999R",
    "date_of_birth": "1990-05-12",
    "first_name": "María",
    "last_name": "García López"
  },
  "validations": [
    {
      "service_id": "esp_dni",
      "service_name": "Spain - DNI/NIE verification",
      "validation": { "is_valid": true, "match_score": 100 },
      "outcome_code": "MATCH",
      "outcome_detail": "All identifiers match the registry record.",
      "source_data": {
        "full_name": "María García López",
        "gender": "F",
        "date_of_birth": "1990-05-12",
        "photo": "https://<media-host>/.../registry_photo.jpg?signature=...",
        "signature": null
      }
    }
  ],
  "match_type": "full_match",
  "status": "Approved",
  "node_id": "first_db_validation",
  "warnings": []
}
```

### Respuesta de cuestionario

Se devuelve por cada envío de cuestionario. Aparece como `questionnaire_responses[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones KYC como KYB. Origen: `questionnaires/serializers/questionnaire.py:591-597` (`QuestionnaireResponseV3Serializer`, que extiende `QuestionnaireResponseSerializer` en `questionnaires/serializers/questionnaire.py:520-588`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `questionnaire_id` | string (UUID) | No | Identificador de la versión del cuestionario que se respondió. | `"6a0f1c2c-…"` |
| `title` | string | No | Nombre del cuestionario, tal como se configuró en la consola. | `"Customer risk profile"` |
| `description` | string | Sí | Descripción del cuestionario. | `"Short risk-profile questions."` |
| `languages` | array of strings | No | Códigos de idioma en los que está publicado el cuestionario. | `["en", "es"]` |
| `default_language` | string | No | Código del idioma de respaldo. | `"en"` |
| `is_active` | boolean | No | Indica si esta versión del cuestionario es la activa. | `true` |
| `is_simple_questionnaire` | boolean | No | `true` cuando el cuestionario no tiene ramificaciones (lista plana). | `true` |
| `questionnaire_group_id` | string (UUID) | No | Identificador compartido por las versiones de un mismo cuestionario. | `"a7c2c2c2-…"` |
| `version` | integer | No | Número de versión de la plantilla activa. | `3` |
| `status` | string | No | Uno de `Approved`, `In Review` o `Not Finished` (un rechazo a nivel de cuestionario se asigna a `In Review`). | `"Approved"` |
| `published_at` | string (ISO 8601) | Sí | Cuándo se publicó la plantilla. | `"2026-01-12T11:00:00Z"` |
| `sections` | array of objects | No | Secciones ordenadas tras aplicar el recorrido del grafo y el filtrado por visibilidad. Cada sección es `{ title, description, items[] }` (title/description provienen del `SECTION_HEADER` de apertura, ya traducidos). Cada elemento es un elemento de formulario (`uuid`, `value` (id del nodo), `element_type`, `is_required`, `title`, `description`, `placeholder`, `choices`, `max_files`, `required_if`, `repeatable_config`, más un campo `answer`, que es `null` cuando no hay respuesta y se omite en los elementos de diseño `HEADING`/`PARAGRAPH`/`SEPARATOR`). Las respuestas de archivo contienen `{ files: [<presigned URL>, …] }`. | `[…]` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_questionnaire"` |

```json theme={null}
{
  "questionnaire_id": "6a0f1c2c-3b7d-4d2c-9eb6-fdc6c7c92ef9",
  "title": "Customer risk profile",
  "description": "Short risk-profile questions.",
  "languages": ["en", "es"],
  "default_language": "en",
  "is_active": true,
  "is_simple_questionnaire": true,
  "questionnaire_group_id": "a7c2c2c2-1111-4d2c-9eb6-fdc6c7c92ef9",
  "version": 3,
  "status": "Approved",
  "published_at": "2026-01-12T11:00:00Z",
  "sections": [
    {
      "title": "Source of funds",
      "description": null,
      "items": [
        {
          "uuid": "4f1d5e2c-aaaa-4d2c-9eb6-fdc6c7c92ef9",
          "value": "q_source_of_funds",
          "element_type": "SINGLE_CHOICE",
          "is_required": true,
          "title": "What is your main source of funds?",
          "description": null,
          "placeholder": null,
          "choices": [
            { "label": "Salary", "value": "salary" },
            { "label": "Business income", "value": "business" },
            { "label": "Investments", "value": "investments" }
          ],
          "max_files": 1,
          "required_if": null,
          "repeatable_config": null,
          "answer": { "value": "salary" }
        }
      ]
    }
  ],
  "node_id": "first_questionnaire"
}
```

### Firma electrónica

Se devuelve por cada firmante de un paso de [Firma electrónica](https://docs.didit.me/es/core-technology/electronic-signature/overview.md). Aparece como `signatures[]` en `GET /v3/session/{sessionId}/decision/` tanto en sesiones KYC como KYB, solo cuando el flujo incluye ese paso. A diferencia de los demás objetos de informe, su `status` es la etapa de firma y su resultado está en `verdict`, y los elementos de su `warnings[]` son `{ code, node_id }` en lugar de [objetos de advertencia](#objeto-de-advertencia).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `id` | string (UUID) | No | La firma del firmante. Úsalo como `signature_id` en las rutas de evidencias y de validación. | `"0e6c2a8e-…"` |
| `node_id` | string | No | Identificador del nodo del flujo. | `"feature_signature"` |
| `status` | string | No | Etapa de firma: `intro`, `review`, `code`, `signing`, `signed` o `declined`. Solo `signed` significa que los documentos están firmados. | `"signed"` |
| `verdict` | string | No | `Not Finished`, `Approved`, `In Review` o `Declined`. | `"Approved"` |
| `level` | string | No | `simple` (predeterminado) o `aes`. `qes` es un complemento que aún no está disponible. | `"aes"` |
| `format` | string | No | `pdf` para una firma simple, `pades` para una firma avanzada (AES). | `"pades"` |
| `profile` | string | Sí | `PAdES-B-LT` una vez firmada una firma avanzada (AES); en caso contrario, null. | `"PAdES-B-LT"` |
| `signer` | object | No | `{ name, capacity, company, role, roles, identity_session_id }`. `capacity` es `self` (KYC) o `company` (KYB). | `{ "name": "Jane Doe", "capacity": "self", … }` |
| `identity_used` | object | No | `{ session_id, kyc_id, verified, expected_name }`: la identidad verificada en la que se basa la firma. Vacío en una firma simple sin identidad verificada. | `{ "verified": true, … }` |
| `certificate` | object | Sí | `{ issuer, issued_to, serial, valid_from, valid_until }`. Es `null` hasta que se firma, y siempre es `null` en una firma simple. | `{ "serial": "5A3F9C21", … }` |
| `confirmation` | objeto | No | `{ channel, destination, confirmed_at, attempts }`. `destination` está enmascarado; `attempts` cuenta los códigos introducidos, incluido el correcto. Una firma Simple no tiene código, por lo que `channel` y `destination` son `null`. | `{ "channel": "email", … }` |
| `timestamp` | objeto | Sí | `{ time, qualified, valid }`. `qualified` siempre es `false` para AES. Es `null` hasta que se firma, y siempre `null` para una firma Simple. | `{ "qualified": false, … }` |
| `documents` | array de objetos | No | `{ id, uuid, title, file_name, pages, size_bytes, sha256_original, sha256_signed, status, opened_at, read_at, read_to_end, consented_at, consent, signed_file, mode, source_format, conversion, fields }`. `status` es `signed`, `declined`, `not_signed` o `not_reached`. `mode` es `fields` o `read_and_agree`. `source_format` es `pdf` o `docx`; `conversion` describe el archivo de Word original, o es `null` para un PDF. | `[…]` |
| `documents[].fields` | array de objetos | No | `{ key, type, role, label, page, x, y, width, height, required, value, display_value, value_source, filled_at, image_url, value_unavailable_reason }` para cada campo del documento. `value` es un string, un booleano para una casilla de verificación, o `true` para una firma o unas iniciales aplicadas. Vacío para un documento sin campos. | `[…]` |
| `adopted_signature` | objeto | Sí | `{ method, font, adopted_at }`: la firma y las iniciales que adoptó el firmante. `method` es `typed` o `drawn`; `font` es el estilo caligráfico de una firma escrita con el teclado. Es `null` hasta que se adopta. | `{ "method": "drawn", … }` |
| `electronic_signature_consent_at` | string (ISO 8601) | Sí | Cuándo aceptó el firmante firmar los documentos electrónicamente. Se establece cuando algún documento tiene campos. | `"2026-11-03T10:41:40Z"` |
| `evidence_file` | string | Sí | Ruta del PDF de evidencias, una vez firmado. | `"/v3/session/…/evidence/?signature_id=…"` |
| `warnings` | array de objetos | No | `{ code, node_id }`, donde `code` es uno de `SIGNATURE_DECLINED`, `SIGNATURE_OTP_FAILED`, `SIGNATURE_NAME_MISMATCH`, `SIGNATURE_IDENTITY_NOT_VERIFIED`, `SIGNATURE_DOCUMENT_CHANGED`. | `[]` |
| `validation` | objeto | Sí | `{ valid, checked_at, documents[] }`: la última comprobación criptográfica de los documentos firmados. Es `null` hasta que se firma. Es `{ valid: null, reason: "signature_provider_outcome_unknown", checked_at }` cuando no se pudo confirmar el resultado de la firma. | `{ "valid": true, … }` |
| `declined_at` | string (ISO 8601) | Sí | Cuándo rechazó el firmante. | `null` |
| `declined_action` | string | No | El `signature_declined_action` del paso. | `"REVIEW"` |
| `signed_at` | string (ISO 8601) | Sí | Cuándo se firmaron los documentos. | `"2026-11-03T10:42:24Z"` |
| `expires_at` | string (ISO 8601) | No | Cuándo deja de funcionar el enlace de firma. | `"2026-11-10T10:30:00Z"` |
| `email_sent_at` | string (ISO 8601) | Sí | Cuándo se envió al firmante una copia firmada por correo electrónico. | `"2026-11-03T10:42:30Z"` |
| `email_unavailable_reason` | string | Sí | Por qué no se envió ninguna copia por correo electrónico, cuando se solicitó una. | `null` |
| `ip_address` | string | Sí | La dirección IP del firmante cuando solicitó su código. | `"203.0.113.10"` |
| `place` | string | Sí | No se recopila: siempre es `null`. | `null` |
| `place_unavailable_reason` | string | Sí | `not_collected`. | `"not_collected"` |

El [informe de firma electrónica](https://docs.didit.me/es/core-technology/electronic-signature/report-electronic-signature.md) incluye un ejemplo completo y todos los campos anidados.

### Estimación de edad

Lo devuelve la API independiente de Estimación de edad (`POST /v3/age-estimation/`). La respuesta contiene un subconjunto de la estructura de [`Liveness check`](#prueba-de-vida) dentro de un envoltorio `age_estimation` (`status`, `method`, `score`, `age_estimation`, `warnings`), además de un bloque `user_image` de detección facial exclusivo de la API independiente; **no** incluye `reference_image`, `video_url`, `matches`, `face_quality` ni `face_luminance`. En las sesiones de un flujo no hay un array separado: la edad estimada aparece como `liveness_checks[].age_estimation` en `GET /v3/session/{sessionId}/decision/`. Fuente: `apis/serializers/age_estimation.py:50-55` (`AgeEstimationResponseSerializer`), con el envoltorio construido en `apis/views/age_estimation.py:138-174`.

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `request_id` | string (UUID) | No | ID de sesión persistido cuando `save_api_request=true` (el valor predeterminado); en caso contrario, un UUID de correlación temporal. | `"3b1f1e2c-…"` |
| `age_estimation` | objeto | No | Envoltorio del resultado: `status` (`Approved` / `Declined`), `method` (siempre `PASSIVE`), `score` (prueba de vida de 0 a 100, admite null), `age_estimation` (edad predicha en años del rostro más grande, admite null), `user_image` (`entities[]` con `age`, `bbox` `[x_min, y_min, x_max, y_max]`, `confidence` y `gender` por rostro; además de `best_angle`), `warnings[]`. | `{ … }` |
| `vendor_data` | string | Sí | El `vendor_data` de la solicitud, devuelto tal cual. | `null` |
| `metadata` | objeto | Sí | El `metadata` de la solicitud, devuelto tal cual. | `null` |
| `created_at` | string (ISO 8601) | No | Marca de tiempo de la solicitud en el servidor. | `"2026-05-17T10:22:13.512941+00:00"` |

```json theme={null}
{
  "request_id": "3b1f1e2c-7777-4d2c-9eb6-fdc6c7c92ef9",
  "age_estimation": {
    "status": "Approved",
    "method": "PASSIVE",
    "score": 94.10,
    "age_estimation": 28.7,
    "user_image": {
      "entities": [
        { "age": 28.7, "bbox": [40, 40, 100, 100], "confidence": 0.72, "gender": "male" }
      ],
      "best_angle": 0
    },
    "warnings": []
  },
  "vendor_data": null,
  "metadata": null,
  "created_at": "2026-05-17T10:22:13.512941+00:00"
}
```

### Autenticación biométrica

La autenticación biométrica ejecuta el mismo pipeline de prueba de vida + coincidencia facial que se usa en el KYC estándar, pero configurado para comparar el rostro capturado con la imagen de referencia de un usuario existente en lugar de con el retrato de un documento recién procesado por OCR. No hay un serializer dedicado: `GET /v3/session/{sessionId}/decision/` devuelve los objetos estándar [Liveness check](#prueba-de-vida) y [Face match](#coincidencia-facial) en `liveness_checks[]` y `face_matches[]`. El flujo de la sesión se configura con `workflow_type = "biometric_authentication"` (`WorkflowTypeChoices`, `common/config/choices.py:636`).

| Campo | Tipo | Admite null | Descripción | Ejemplo |
| - | - | - | - | - |
| `liveness_checks` | array de [Liveness check](#prueba-de-vida) | No | Resultado de la prueba de vida para el intento de autenticación. | `[ { "status": "Approved", … } ]` |
| `face_matches` | array de [Face match](#coincidencia-facial) | No | Resultado de la coincidencia con la referencia registrada. `source_image_session_id` toma el valor del propio `session_id` de la sesión: el rostro de referencia (el `portrait_image` proporcionado, o el rostro almacenado que se reutiliza mediante `vendor_data` cuando se omite `portrait_image`) se registra en la propia sesión de autenticación (`face/views/face.py:656-659`). | `[ { "status": "Approved", "source_image_session_id": "…", … } ]` |
| `status` | string | No | Estado de la sesión en el nivel superior (consulta [Enum de estado](#referencia-de-los-valores-de-estado)). | `"Approved"` |

```json theme={null}
{
  "session_id": "9b1f1e2c-8888-4d2c-9eb6-fdc6c7c92ef9",
  "status": "Approved",
  "liveness_checks": [
    {
      "status": "Approved",
      "method": "PASSIVE",
      "score": 95.10,
      "reference_image": "https://<media-host>/.../reference.jpg?signature=...",
      "video_url": null,
      "age_estimation": null,
      "matches": [],
      "face_quality": 91.20,
      "face_luminance": 53.10,
      "node_id": "biometric_auth_liveness",
      "warnings": []
    }
  ],
  "face_matches": [
    {
      "status": "Approved",
      "score": 98.42,
      "source_image_session_id": "9b1f1e2c-8888-4d2c-9eb6-fdc6c7c92ef9",
      "source_image": "https://<media-host>/.../source.jpg?signature=...",
      "target_image": "https://<media-host>/.../target.jpg?signature=...",
      "node_id": "biometric_auth_face_match",
      "warnings": []
    }
  ]
}
```

### Registro KYB

Se devuelve por cada empresa confirmada en el registro dentro de un flujo de verificación (workflow) KYB. Aparece como `registry_checks[]` en `GET /v3/session/{sessionId}/decision/` para las sesiones de empresa. Fuente: `kyb/serializers/kyb.py:939-964` (`RegistryCheckV3Serializer`).

| Campo | Tipo | Admite nulo | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_registry"` |
| `data_resolved` | boolean | No | `true` cuando la consulta al registro ha finalizado (o `is_from_registry` es `false`, lo que significa que los datos se introdujeron manualmente). | `true` |
| `company` | object | No | Payload completo de la empresa: consulta [Objeto de empresa](#objeto-de-empresa) más abajo. | `{ … }` |
| `ownership_structure` | object | Sí | La tabla de capitalización que acreditó el registro: `shareholders[]` y `beneficial_owners[]`, cada propietario con su identidad en el registro, su participación y su `shareholding` canónico. | `{ "shareholders": [...], "beneficial_owners": [] }` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

#### Objeto de empresa

Procede de `kyb/serializers/kyb.py:220-321` (`KYBCompanyResponseSerializer`).

| Campo | Tipo | Admite nulo | Descripción |
| - | - | - | - |
| `uuid` | string (UUID) | No | Identificador interno de la empresa. |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo. |
| `status` | string | No | Estado de la función (`FeatureStatusChoices`). |
| `registry_status` | string | Sí | Estado de la empresa según el registro (`active`, `dissolved`, …). |
| `data_resolved` | boolean | No | Misma definición que en el objeto padre. |
| `company_name` | string | Sí | Razón social registrada de la empresa. |
| `registration_number` | string | Sí | Identificador en el registro. |
| `country_code` | string (ISO 3166-1 alpha-2) | Sí | País de constitución. |
| `region` | string | Sí | Subdivisión ISO 3166-2 cuando corresponda (p. ej., `US-CA`). |
| `company_type` | string | Sí | Forma jurídica (`LLC`, `SL`, …). |
| `incorporation_date` | string (YYYY-MM-DD) | Sí | Fecha de constitución. |
| `registered_address` | string | Sí | Domicilio legal registrado. |
| `tax_number` | string | Sí | Identificación fiscal / número de IVA. |
| `risk_level` | string | Sí | Calificación de riesgo facilitada por el proveedor. |
| `verification_status` | string | Sí | Enum interno del estado de verificación. |
| `is_from_registry` | boolean | No | `true` cuando los datos proceden del registro (frente a la introducción manual). |
| `fetch_status` | string | Sí | `pending`, `resolved`, `failed`. |
| `alternative_names` | string | Sí | Nombres comerciales alternativos separados por comas. |
| `nature_of_business` | string | Sí | Descripción en texto libre de la actividad de la empresa. |
| `registered_capital` | string | Sí | Capital social como cadena legible. |
| `registered_capital_amount` | string (decimal) | Sí | Importe del capital social ya interpretado. |
| `registered_capital_currency` | string (ISO 4217) | Sí | Código de moneda. |
| `website` | string (URL) | Sí | Sitio web de la empresa. |
| `email` | string | Sí | Correo electrónico de contacto público. |
| `phone` | string | Sí | Teléfono de contacto público. |
| `legal_entity_identifier` | string | Sí | LEI, cuando está disponible. |
| `location_of_registration` | string | Sí | Oficina o región del registro. |
| `vat_number` | string | Sí | Número de IVA enviado para la empresa. |
| `vat_validation_status` | string | No | Resultado de validar el número de IVA, o el `tax_number` cuando no lo hay: `valid`, `invalid`, `format_valid`, `invalid_format`, `could_not_validate` o `not_applicable`. Consulta [Validación del IVA y de la identificación fiscal](https://docs.didit.me/es/business-verification/company-data.md#validación-del-iva-y-de-la-identificación-fiscal). |
| `vat_validated_number` | string | Sí | El número que se comprobó, tal como lo conoce la fuente. |
| `vat_validation_source` | string | Sí | Fuente que determinó el estado: `eu_vies`, `pl_vat_white_list`, `no_brreg`, `ch_uid_register`, `br_receita_federal`, `co_rues`, `cr_hacienda`, `ec_sri`, `py_dnit` o `format_rules`. |
| `vat_validated_name` | string | Sí | Nombre registrado en la fuente (vacío cuando no lo revela). |
| `vat_validated_address` | string | Sí | Dirección registrada en la fuente (vacía cuando no se revela). |
| `vat_checked_at` | string (ISO 8601) | Sí | Marca de tiempo de la comprobación; `null` cuando no se realizó ninguna comprobación. |
| `financial_summary` | object | Sí | Resumen de los datos financieros más recientes cuando el registro los proporciona. |
| `officers` | array of objects | No | Lista de directivos apta para B2C: `{ uuid, name, designation, role, nationality, is_active, kyc_status, kyc_session_url }`. |
| `beneficial_owners` | array of objects | No | Lista de UBO apta para B2C: `{ uuid, name, first_name, last_name, entity_type, roles, ownership_min_shares, ownership_max_shares, is_active, kyc_status, kyc_session_url, effective_ownership_percent }`. |
| `addresses` | array of objects | Sí | Detalle de cada dirección según el registro. |
| `industries` | array of objects | Sí | Clasificaciones de tipo SIC/NAICS. |
| `accounts` | array of objects | Sí | Metadatos de las cuentas depositadas. |
| `registry_data` | object | Sí | Detalle normalizado del registro elaborado por Didit (resultado de la propiedad, correcciones hechas en la consola, datos del registro sin campo propio). No es un contrato estable. |
| `user_provided_data` | object | Sí | Instantánea de los campos editados por el usuario. |
| `confirmed_by_user_at` | string (ISO 8601) | Sí | Marca de tiempo en que el usuario confirmó los datos extraídos. |
| `last_console_edit_at` | string (ISO 8601) | Sí | Marca de tiempo de la última edición en la consola. |
| `is_editable` | boolean | No | `true` mientras el usuario final aún puede editar los datos procedentes del registro. |

```json theme={null}
{
  "status": "Approved",
  "node_id": "first_registry",
  "data_resolved": true,
  "company": {
    "uuid": "b1f1e2c2-9999-4d2c-9eb6-fdc6c7c92ef9",
    "node_id": "first_registry",
    "status": "Approved",
    "registry_status": "active",
    "data_resolved": true,
    "company_name": "Sante Clinics SL",
    "registration_number": "B12345678",
    "country_code": "ES",
    "region": null,
    "company_type": "SL",
    "incorporation_date": "2018-03-22",
    "registered_address": "Calle Mayor 1, 28001 Madrid, Spain",
    "tax_number": "B12345678",
    "risk_level": "low",
    "verification_status": "verified",
    "is_from_registry": true,
    "fetch_status": "resolved",
    "alternative_names": "Sante Clinics",
    "nature_of_business": "Medical clinic operations",
    "registered_capital": "EUR 50,000",
    "registered_capital_amount": "50000.00",
    "registered_capital_currency": "EUR",
    "website": "https://santeclinics.com",
    "email": "info@santeclinics.com",
    "phone": "+34911223344",
    "legal_entity_identifier": null,
    "location_of_registration": "Registro Mercantil de Madrid",
    "vat_number": "ESB12345678",
    "vat_validation_status": "valid",
    "vat_validated_name": "SANTE CLINICS SL",
    "vat_validated_address": "CALLE MAYOR 1, 28001 MADRID",
    "vat_checked_at": "2026-05-17T10:11:05Z",
    "financial_summary": null,
    "officers": [
      {
        "uuid": "c1f1e2c2-aaaa-4d2c-9eb6-fdc6c7c92ef9",
        "name": "María García López",
        "designation": "Administrador único",
        "role": "Director",
        "nationality": "ESP",
        "is_active": true,
        "kyc_status": "Approved",
        "kyc_session_url": "https://verify.didit.me/s/…"
      }
    ],
    "beneficial_owners": [
      {
        "uuid": "d1f1e2c2-bbbb-4d2c-9eb6-fdc6c7c92ef9",
        "name": "María García López",
        "first_name": "María",
        "last_name": "García López",
        "entity_type": "person",
        "roles": ["UBO"],
        "ownership_min_shares": "75.00",
        "ownership_max_shares": "75.00",
        "is_active": true,
        "kyc_status": "Approved",
        "kyc_session_url": "https://verify.didit.me/s/…",
        "effective_ownership_percent": 75.0
      }
    ],
    "addresses": [],
    "industries": [],
    "accounts": [],
    "registry_data": {},
    "user_provided_data": {},
    "confirmed_by_user_at": "2026-05-17T10:11:02Z",
    "last_console_edit_at": null,
    "is_editable": false
  },
  "ownership_structure": null,
  "warnings": []
}
```

### Documento KYB

Se devuelve por cada nodo que recopila documentos justificativos de KYB. Aparece como `document_verifications[]` en `GET /v3/session/{sessionId}/decision/` para las sesiones de empresa: una entrada por cada `node_id`, con `items[]` que enumera cada documento subido. Fuente: `kyb/serializers/kyb.py:1053-1068` (`DocumentVerificationV3Serializer`); cada elemento sigue `kyb/serializers/kyb.py:811-851` (`KYBDocumentResponseSerializer`).

| Campo | Tipo | Admite nulo | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Estado agregado de los documentos de este nodo: `Approved` solo cuando todos los documentos del pipeline están aprobados; `Declined` si alguno está rechazado; `In Review` en cualquier otro caso; `Not Finished` mientras esté pendiente. Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_kyb_documents"` |
| `items` | array de [objetos de elemento de documento KYB](#objeto-de-elemento-de-documento-kyb) | No | Una entrada por cada documento subido o solicitado. | `[…]` |
| `groups` | objeto | No | Recuentos por grupo de documentos: `{ <group_name>: { total, approved, pending, declined, in_review, other, missing } }`. | `{ "incorporation_certificate": { "total": 1, "approved": 1, "pending": 0, "declined": 0, "in_review": 0, "other": 0, "missing": 0 } }` |
| `required_groups` | array de strings | No | Grupos de documentos que exige la configuración del flujo. | `["incorporation_certificate", "shareholder_register"]` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

#### Objeto de elemento de documento KYB

| Campo | Tipo | Nulable | Descripción |
| - | - | - | - |
| `uuid` | string (UUID) | No | Identificador interno del documento. |
| `document_type` | string | Sí | Grupo de alto nivel (`incorporation_certificate`, `shareholder_register`, …). |
| `document_subtype` | string | Sí | Subtipo específico del proveedor. |
| `document_group` | string | Sí | Copia de `document_type` (alias que se mantiene por claridad). |
| `file_url` | string (URL) | Sí | URL prefirmada al archivo depurado. |
| `original_filename` | string | Sí | Nombre del archivo tal como se subió. |
| `file_size` | integer | Sí | Tamaño del archivo en bytes. |
| `status` | string | No | Estado de cada documento (`FeatureStatusChoices`). |
| `created_at` | string (ISO 8601) | No | Marca de tiempo de la subida. |
| `cross_check_result` | objeto | Sí | Veredicto de la verificación cruzada con el registro u otros documentos. |
| `document_metadata` | objeto | Sí | Misma estructura de metadatos filtrados que el `document_metadata` de la prueba de domicilio. |
| `description` | string | Sí | Descripción proporcionada por el revisor o por el sistema. |
| `is_requested` | boolean | No | `true` cuando el flujo esperaba este documento. |
| `ocr_data` | objeto | Sí | Campos extraídos por OCR, cuando estén disponibles. |
| `is_console_upload` | boolean | No | `true` cuando el documento lo subió un revisor desde la consola (se excluye del veredicto agregado). |
| `is_confirmed` | boolean | No | `true` cuando el revisor ha confirmado explícitamente el documento. |

```json theme={null}
{
  "status": "Approved",
  "node_id": "first_kyb_documents",
  "items": [
    {
      "uuid": "e1f1e2c2-cccc-4d2c-9eb6-fdc6c7c92ef9",
      "document_type": "incorporation_certificate",
      "document_subtype": "registro_mercantil_extract",
      "document_group": "incorporation_certificate",
      "file_url": "https://<media-host>/.../incorporation.pdf?signature=...",
      "original_filename": "incorporation_certificate.pdf",
      "file_size": 256412,
      "status": "Approved",
      "created_at": "2026-05-17T10:08:00Z",
      "cross_check_result": { "matches_registry_name": true, "matches_registration_number": true },
      "document_metadata": {
        "file_size": 256412,
        "content_type": "application/pdf",
        "is_signed": true,
        "is_tampered": false
      },
      "description": null,
      "is_requested": true,
      "ocr_data": { "company_name": "Sante Clinics SL", "registration_number": "B12345678" },
      "is_console_upload": false,
      "is_confirmed": true
    }
  ],
  "groups": {
    "incorporation_certificate": { "total": 1, "approved": 1, "pending": 0, "declined": 0, "in_review": 0, "other": 0, "missing": 0 }
  },
  "required_groups": ["incorporation_certificate", "shareholder_register"],
  "warnings": []
}
```

### Persona clave de KYB

Se devuelve por cada nodo de Personas clave de un flujo KYB. Aparece como `key_people_checks[]` en `GET /v3/session/{sessionId}/decision/` para las sesiones de empresas. Fuente: `kyb/serializers/kyb.py:967-1050` (`KeyPeopleCheckV3Serializer`).

| Campo | Tipo | Nulable | Descripción | Ejemplo |
| - | - | - | - | - |
| `status` | string | No | Consulta [Enum de estado](#referencia-de-los-valores-de-estado). | `"Approved"` |
| `node_id` | string \| null | Sí | Identificador del nodo del flujo (V3). | `"first_key_people"` |
| `registry` | objeto | No | `{ officers[], beneficial_owners[] }` extraídos del registro. Los cargos directivos siguen `KYBPersonResponseSerializer` (`kyb/serializers/kyb.py:533-645`); los beneficiarios finales siguen `KYBBeneficialOwnerResponseSerializer` (`kyb/serializers/kyb.py:648-788`, que añade `date_of_birth`, `country_of_birth`, `email`, `company_name`, `registration_number`, `entity_type`, `roles`, `ownership_min_shares`, `ownership_max_shares`, `child_beneficial_owners`, `effective_ownership_percent`). Ambos incluyen el enriquecimiento AML + KYC de cada parte (`aml_status`, `kyc_status`, `kyc_session_url`, `kyc_session_id`, `verification_workflow_type`, `verification_workflow_id`, `verification_workflow_label`, `verification_workflow_features`, `didit_internal_id`, `kyc_document_type`, `kyc_nationality`, `kyc_liveness_passed`, `kyc_verified_at`, `kyc_aml_categories`, `kyc_notification_sent_at`). | `{ "officers": [...], "beneficial_owners": [...] }` |
| `submitted` | objeto | No | `{ parties[] }`: entradas que la empresa confirmó o envió mediante el flujo de personas clave (filas `BusinessParty` con `source=USER`). Cada parte sigue `BusinessPartySubmissionResponseSerializer` (`kyb/serializers/party.py:146-194`): `uuid`, `entity_type`, `source`, `name`, `first_name`, `last_name`, `company_name`, `registration_number`, `email`, `nationality`, `phone_number`, `date_of_birth`, `position`, `custom_fields`, `is_active`, `is_skipped`, `requires_verification`, `roles[]` (`{ role, ownership_percent, voting_percent }`), `kyc_session_id`, `kyc_session_status`, `kyc_session_url`, `kyc_session_deleted`, `kyb_sub_session_id`, `kyb_sub_session_status`, `kyb_sub_session_url`, `kyb_sub_session_deleted`, `verification_workflow_type`, `verification_workflow_id`, `verification_workflow_label`, `verification_workflow_features`, `didit_internal_id`. `kyc_session_deleted` / `kyb_sub_session_deleted` marcan una sesión hija que se eliminó: su estado queda congelado en el valor que tuviera, el `*_session_url` correspondiente se devuelve como `null` porque el enlace ya no resuelve, y la parte deja de bloquear a la sesión principal (en su lugar, la comprobación pasa a `In Review`). Para limpiarlo, usa [`PATCH /v3/session/{id}/kyb/parties/{party_uuid}/`](https://docs.didit.me/es/sessions-api/update-data#omitir-a-una-parte-de-personas-clave). | `{ "parties": [...] }` |
| `ubo_kyc_summary` | objeto | Sí | Recuentos de los UBO activos con KYC vinculado: `{ total, approved, flagged, pending }`. `null` cuando ningún UBO activo tiene KYC vinculado. | `{ "total": 2, "approved": 2, "flagged": 0, "pending": 0 }` |
| `warnings` | array | No | Consulta [Objeto de advertencia](#objeto-de-advertencia). | `[]` |

```json theme={null}
{
  "status": "Approved",
  "node_id": "first_key_people",
  "registry": {
    "officers": [
      {
        "uuid": "c1f1e2c2-aaaa-4d2c-9eb6-fdc6c7c92ef9",
        "name": "María García López",
        "designation": "Administrador único",
        "role": "Director",
        "nationality": "ESP",
        "appointment_date": "2018-03-22",
        "termination_date": null,
        "is_active": true,
        "address": "Calle Mayor 1, 28001 Madrid",
        "aml_status": "Approved",
        "kyc_status": "Approved",
        "kyc_session_url": "https://verify.didit.me/s/…",
        "kyc_session_id": "9b1f1e2c-8888-4d2c-9eb6-fdc6c7c92ef9",
        "verification_workflow_type": "kyc",
        "verification_workflow_id": "11111111-1111-1111-1111-111111111111",
        "verification_workflow_label": "KYB officer KYC",
        "verification_workflow_features": [
          { "feature": "ID_VERIFICATION", "status": "Approved" },
          { "feature": "LIVENESS", "status": "Approved" },
          { "feature": "FACE_MATCH", "status": "Approved" }
        ],
        "didit_internal_id": "user-12345",
        "kyc_document_type": "Passport",
        "kyc_nationality": "ESP",
        "kyc_liveness_passed": true,
        "kyc_verified_at": "2026-05-17T10:10:11Z",
        "kyc_aml_categories": [],
        "kyc_notification_sent_at": "2026-05-15T08:00:00Z"
      }
    ],
    "beneficial_owners": []
  },
  "submitted": {
    "parties": [
      {
        "uuid": "d1f1e2c2-bbbb-4d2c-9eb6-fdc6c7c92ef9",
        "entity_type": "person",
        "source": "USER",
        "name": "María García López",
        "first_name": "María",
        "last_name": "García López",
        "company_name": null,
        "registration_number": null,
        "email": "maria.garcia@example.com",
        "nationality": "ESP",
        "phone_number": null,
        "date_of_birth": "1990-05-12",
        "position": "Administrador único",
        "custom_fields": {},
        "is_active": true,
        "is_skipped": false,
        "requires_verification": true,
        "roles": [
          { "role": "UBO", "ownership_percent": 75.0, "voting_percent": null }
        ],
        "kyc_session_id": "9b1f1e2c-8888-4d2c-9eb6-fdc6c7c92ef9",
        "kyc_session_status": "Approved",
        "kyc_session_url": "https://verify.didit.me/s/…",
        "kyb_sub_session_id": null,
        "kyb_sub_session_status": null,
        "kyb_sub_session_url": null,
        "verification_workflow_type": "kyc",
        "verification_workflow_id": "11111111-1111-1111-1111-111111111111",
        "verification_workflow_label": "KYB officer KYC",
        "verification_workflow_features": [
          { "feature": "ID_VERIFICATION", "status": "Approved" },
          { "feature": "LIVENESS", "status": "Approved" }
        ],
        "didit_internal_id": "user-12345"
      }
    ]
  },
  "ubo_kyc_summary": { "total": 1, "approved": 1, "flagged": 0, "pending": 0 },
  "warnings": []
}
```

## Campos a nivel de decisión

Estas claves están junto a los arrays de cada función en `GET /v3/session/{sessionId}/decision/` y dentro del objeto `decision` de un webhook.

| Campo | Tipo | Admite nulo | Descripción |
| - | - | - | - |
| `status_override` | objeto | Sí | `{ overridden_at, automatic_status }` después de que un revisor haya establecido `status` manualmente; `null` cuando el estado es el automático. |
| `decision_trace` | objeto | No | Cómo se llegó al estado: `status`, `decided_by` (`manual`, `automatic` o `investigator`), `decided_at`, `automatic_status`, `terminal_node_id`, `actor`, `warning_counts` y `status_warnings`. |
| `linked_records` | objeto | Sí | Resúmenes de `same_face`, `earlier_verifications` y `networks`; `null` cuando no hay nada que mostrar. |
| `biometric_retention` | objeto | No | `{ jurisdictions, deletes_at }`. `deletes_at` es la fecha en la que se eliminan los datos biométricos de la sesión capturados en directo, y `null` cuando aún no hay una fecha aplicable. |
| `database_validation_not_performed_reason` | objeto | Sí | `{ code, message }` que explica por qué una validación de base de datos configurada no produjo ningún resultado. |
| `assignee`, `waiting_since`, `sla_due_at` | objeto, datetime | Sí | El revisor de la Console que tiene asignada la sesión y su temporizador de revisión; el reloj es `null` salvo que la sesión esté en `In Review`. |
| `shared_from_session`, `shared_from_session_number` | UUID, entero | Sí | La sesión de origen de una sesión importada. |
| `sandbox_scenario` | cadena | Sí | El escenario con el que se creó una sesión de sandbox. |
| `fraud_check` | objeto | Sí | El resultado de la Fraud Check API; `null` en cualquier otra sesión. |
| `full_session_video`, `full_session_video_recorded_at` | URL, datetime | Sí | La grabación y el momento en que se realizó. Solo se devuelve cuando tu organización graba el video de la sesión completa. |

Consulta [Obtener una sesión](https://docs.didit.me/es/sessions-api/retrieve-session.md#campos-de-estado-traza-de-la-decisión-y-revisión) para saber cómo leerlos.

## Consentimiento biométrico

Cada decisión y webhook de sesión de Verificación de usuarios incluye un único objeto `biometric_consent` (no un array): si la sesión requería consentimiento biométrico explícito, por qué y la evidencia de la respuesta. Es `null` cuando la sesión nunca se evaluó, por ejemplo en un flujo de verificación (workflow) sin captura facial. Origen: `BiometricConsentDecisionSerializer` (`sessions/serializers/biometric_consent.py`). Cuándo aparece el paso y qué significa cada caso se explica en [Consentimiento biométrico](https://docs.didit.me/es/getting-started/biometric-consent.md).

Los campos sin valor registrado son `null`, nunca una cadena vacía.

| Campo | Tipo | Descripción |
| - | - | - |
| `required` | boolean | Si la sesión debe recoger consentimiento biométrico explícito. Nunca vuelve a `false`. |
| `trigger` | string (enum) \| null | Por qué se requiere el consentimiento, o cómo se cumplió: `declared_state`, `ip_state`, `ip_unknown`, `document_issuer`, `forced` (el modo de la aplicación es Siempre), `customer_collected` (enviaste `biometric_consent` al crear la sesión). `null` mientras no se requiera. |
| `status` | string (enum) | `not_required`, `pending` (requerido, no otorgado), `given`, `declined` (se registró un rechazo; hoy ninguna pantalla de Didit ofrece rechazar). |
| `given_at` | string (ISO 8601) \| null | Cuándo se otorgó el consentimiento. Para `customer_collected`, el `given_at` que enviaste. |
| `declined_at` | string (ISO 8601) \| null | Cuándo se registró un rechazo. |
| `text_version` | string \| null | ID de versión del texto de consentimiento al que respondió la persona, o el que enviaste. |
| `text_hash` | string \| null | SHA-256 (hex) del texto exacto mostrado, en el idioma en que se mostró. |
| `locale` | string \| null | Idioma en que se mostró el texto. |
| `policy_url` | string \| null | La política de datos biométricos a la que enlazaba el paso. |
| `step` | string \| null | Paso del flujo en el que estaba la sesión cuando la persona respondió (por ejemplo, `LIVENESS`). |
| `node_id` | string \| null | Nodo del grafo del flujo en el que estaba la sesión cuando la persona respondió. |
| `ip_address` | string \| null | IP desde la que llegó la respuesta. |
| `ip_country_code` | string \| null | País ISO 3166-1 alfa-2 de la IP de la respuesta. |
| `ip_state` | string \| null | Subdivisión ISO 3166-2 de la IP de la respuesta (por ejemplo, `US-IL`). |
| `ip_city` | string \| null | Ciudad de la IP de la respuesta. |
| `user_agent` | string \| null | User agent de la solicitud de la respuesta. |
| `detected_ip_address` | string \| null | La IP de la persona desde la que se evaluó el requisito por última vez. Puede diferir de `ip_address` cuando la persona respondió en otro dispositivo. |
| `detected_country_code` | string \| null | País ISO 3166-1 alfa-2 de la IP detectada. |
| `detected_state` | string \| null | Subdivisión ISO 3166-2 de la IP detectada. |
| `detected_city` | string \| null | Ciudad de la IP detectada. |
| `declared_state` | string \| null | Subdivisión ISO 3166-2 que declaraste: `user_state`, o el estado de una dirección de EE. UU. en `expected_details`. |
| `document_state` | string \| null | Subdivisión ISO 3166-2 que emitió el documento de identidad, leída en la captura del documento. |
| `jurisdictions` | array of string | Estados de EE. UU. (códigos USPS, por ejemplo `IL`) cuya legislación biométrica se aplica a la persona. `US` cuando la evidencia sitúa a la persona en EE. UU. pero no se conoce el estado. Vacío cuando no aplica ninguno. |
| `retention_months` | integer \| null | El límite de retención biométrica más corto, en meses, entre `jurisdictions`. `null` cuando no aplica ninguno. |
| `reason` | string (enum) \| null | `BIOMETRIC_CONSENT_UNSUPPORTED_SDK`: se requería consentimiento y un SDK nativo anterior a 4.10.0, o uno que no informó su versión, capturó un rostro sin el paso; `status` se queda en `pending`, o en `given` si la persona aceptó después en el flujo alojado. `BIOMETRIC_CONSENT_DECLINED`: se registró un rechazo (sustituye al motivo del SDK). `null` en los demás casos, y siempre `null` cuando la sesión no requería consentimiento. |
| `decline_reason` | string \| null | `BIOMETRIC_CONSENT_DECLINED` cuando un rechazo registrado terminó la sesión; en caso contrario, `null`. |
| `face_data_deleted_at` | string (ISO 8601) \| null | Cuándo el rechazo eliminó las imágenes faciales, los vídeos y las plantillas faciales de la sesión. `null` salvo que se haya registrado un rechazo. |

Una sesión en Illinois realizada mediante un SDK nativo anterior a 4.10.0, que capturó la selfie sin el paso:

```json theme={null}
{
  "required": true,
  "trigger": "ip_state",
  "status": "pending",
  "given_at": null,
  "declined_at": null,
  "text_version": null,
  "text_hash": null,
  "locale": null,
  "policy_url": null,
  "step": null,
  "node_id": null,
  "ip_address": null,
  "ip_country_code": null,
  "ip_state": null,
  "ip_city": null,
  "user_agent": null,
  "detected_ip_address": "203.0.113.42",
  "detected_country_code": "US",
  "detected_state": "US-IL",
  "detected_city": "Chicago",
  "declared_state": null,
  "document_state": null,
  "jurisdictions": ["IL"],
  "retention_months": 36,
  "reason": "BIOMETRIC_CONSENT_UNSUPPORTED_SDK",
  "decline_reason": null,
  "face_data_deleted_at": null
}
```

Una persona en una VPN con salida fuera de EE. UU., que aceptó en el flujo alojado:

```json theme={null}
{
  "required": true,
  "trigger": "declared_state",
  "status": "given",
  "given_at": "2026-10-13T18:31:07.412000Z",
  "declined_at": null,
  "text_version": "bio-consent-2026-10-12",
  "text_hash": "9b2f0c5e4d8a7f61c3e2b4a5d6f7081923a4b5c6d7e8f90a1b2c3d4e5f6a7b8c",
  "locale": "en",
  "policy_url": "https://didit.me/legal/biometric-data-policy",
  "step": "LIVENESS",
  "node_id": "feature_liveness_1",
  "ip_address": "198.51.100.23",
  "ip_country_code": "ES",
  "ip_state": "ES-M",
  "ip_city": "Madrid",
  "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
  "detected_ip_address": "198.51.100.23",
  "detected_country_code": "ES",
  "detected_state": "ES-M",
  "detected_city": "Madrid",
  "declared_state": null,
  "document_state": null,
  "jurisdictions": ["IL"],
  "retention_months": 36,
  "reason": null,
  "decline_reason": null,
  "face_data_deleted_at": null
}
```

## Referencia de los valores de estado

Dos conjuntos de valores relacionados comparten el nombre de campo `status`. Todos los objetos de informe por función de esta página usan el enum de nivel de función; el `status` de nivel superior de la sesión principal usa el enum de sesión, más amplio.

### Estados de nivel de función

Los usa el campo `status` de todos los objetos de informe. Origen: `common/config/choices.py:343-348` (`FeatureStatusChoices`).

| Valor | Significado |
| - | - |
| `Not Finished` | La función se ha habilitado, pero el usuario aún no la ha completado. |
| `Approved` | La función superó todas las comprobaciones. |
| `Declined` | La función no superó al menos una comprobación estricta (consulta `warnings[]` con `log_type: "error"`). |
| `In Review` | La función activó señales de fallo leve y está pendiente de revisión manual (consulta `warnings[]` con `log_type: "warning"`). |
| `Resub Requested` | Un revisor solicitó que el usuario vuelva a enviar la información de esta función. |

La verificación de teléfono, la de correo electrónico y la de identidad también pueden devolver `Expired` cuando se agota el tiempo de su paso (`PhoneStatusChoices` en `common/config/choices.py:377-382`, `EmailStatusChoices` en `common/config/choices.py:434-439`).

### Estados de nivel de sesión

Los usa el `status` de nivel superior de la sesión principal. Origen: `common/config/choices.py:106-117` (`StatusChoices`).

| Valor | Significado |
| - | - |
| `Not Started` | La sesión se ha creado, pero el usuario no la ha iniciado. |
| `In Progress` | El usuario ha iniciado el flujo; el resultado aún no es definitivo. |
| `Approved` | La sesión superó todas las comprobaciones. |
| `Declined` | La sesión no superó al menos una comprobación estricta. |
| `In Review` | La sesión está pendiente de revisión manual. |
| `Expired` | La sesión expiró antes de completarse. |
| `Abandoned` | El usuario abandonó el flujo sin completarlo. |
| `Kyc Expired` | Venció el periodo de validez del KYC (se usa en flujos de reverificación). |
| `Resubmitted` | El usuario volvió a enviar la verificación tras un rechazo previo; una sesión más reciente reemplaza a esta. |
| `Awaiting User` | El sistema está esperando una acción del usuario (por ejemplo, introducir un OTP). |

> [!TIP]
>
> Los valores finales de sesión son `Approved`, `Declined`, `In Review`, `Expired`, `Kyc Expired` y `Abandoned`. Una sesión puede alcanzar su decisión global mientras una función concreta sigue en `In Review`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.