> ## 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.

# Estados de verificación: ciclo de vida y códigos

> Estados de sesión de Didit: Approved, Declined, In Review, Expired, Resubmitted, Abandoned y KYC Expired. Gestiona decisiones, reintentos y webhooks.

Cada sesión de verificación pasa por una serie de estados. Conocerlos te ayuda a seguir el progreso de los usuarios, automatizar las decisiones de cumplimiento y optimizar la conversión.

Este enum es la única fuente de verdad para las cadenas que devuelven `GET /v3/session/<id>/decision/` y todos los webhooks de Didit.

***

## Todos los valores de estado

> [!NOTE]
>
> Cada estado es una **cadena exacta** que devuelven la API y los webhooks de Didit. Usa siempre una comparación estricta de cadenas (por ejemplo, `=== "In Review"`) en tu código: estos valores distinguen entre mayúsculas y minúsculas e incluyen espacios. El valor `Kyc Expired` además lleva una sola `K` mayúscula (no `KYC`).

| Estado | Valor de la cadena | Descripción |
| - | - | - |
| No iniciada | `"Not Started"` | Sesión creada; el usuario no ha abierto el enlace |
| En curso | `"In Progress"` | El usuario está completando la verificación |
| Aprobada | `"Approved"` | Todas las comprobaciones se superaron: identidad verificada |
| Rechazada | `"Declined"` | Una o más comprobaciones fallaron |
| En revisión | `"In Review"` | Marcada para revisión manual de cumplimiento |
| Pendiente del usuario | `"Awaiting User"` | A la espera de que una o más partes completen su verificación (KYB) |
| Reenviada | `"Resubmitted"` | Se pidió al usuario que repita pasos concretos |
| Expirada | `"Expired"` | La sesión caducó antes de que el usuario abriera el enlace |
| Abandonada | `"Abandoned"` | El usuario empezó, pero no terminó a tiempo |
| KYC expirado | `"Kyc Expired"` | Sesión aprobada anteriormente cuyo documento verificado superó su fecha de caducidad |

***

## Estados de sesión

> [accordion] No iniciada — "Not Started"
>
> **Valor en la API:** `"Not Started"`
>
> La sesión se creó mediante la API, pero el usuario **todavía no ha abierto el enlace de verificación**.
>
> * **Qué hacer:** espera a que el usuario empiece o envíale un recordatorio si pasa demasiado tiempo.
> * **Pasa a:** `"In Progress"`, `"Expired"`

> [accordion] En curso — "In Progress"
>
> **Valor en la API:** `"In Progress"`
>
> El usuario abrió el enlace y **está completando los pasos de verificación** (captura del documento, prueba de vida, etc.).
>
> * **Qué hacer:** no hace falta ninguna acción: el usuario está avanzando por el flujo.
> * **Pasa a:** `"Approved"`, `"Declined"`, `"In Review"`, `"Abandoned"`

> [accordion] Aprobada — "Approved"
>
> **Valor en la API:** `"Approved"`
>
> Todas las comprobaciones de verificación **se superaron correctamente**. La identidad del usuario quedó verificada.
>
> * **Qué hacer:** concede acceso al usuario, actualiza su perfil y guarda los datos de la decisión.
> * **El webhook incluye:** el objeto `decision` completo con los resultados de todas las funciones.
> * **Pasa a:** `"Kyc Expired"` (cuando vence la fecha de caducidad del documento verificado; es el comportamiento predeterminado, salvo que **Expiration mode** esté en **Allow expired** para ese país y tipo de documento). Un revisor o el endpoint de actualización de estado también pueden cambiarla a `"Declined"` o `"Resubmitted"`.

> [accordion] Rechazada — "Declined"
>
> **Valor en la API:** `"Declined"`
>
> Al menos una comprobación de verificación **falló**. El usuario no superó la verificación.
>
> * **Qué hacer:** notifica al usuario. Si el problema tiene solución, puedes solicitar un reenvío.
> * **El webhook incluye:** el objeto `decision` completo con advertencias que explican el fallo.
> * **Pasa a:** `"Resubmitted"` (si un revisor lo solicita). Un revisor o el endpoint de actualización de estado también pueden cambiarla a `"Approved"`.

> [accordion] En revisión — "In Review"
>
> **Valor en la API:** `"In Review"`
>
> Las comprobaciones automáticas detectaron **advertencias que requieren revisión humana**. Un revisor de cumplimiento debe tomar la decisión final.
>
> * **Qué hacer:** un revisor debe abrir la sesión en la consola y aprobarla, rechazarla o solicitar un reenvío.
> * **El webhook incluye:** el objeto `decision` completo con las advertencias.
> * **Pasa a:** `"Approved"`, `"Declined"`, `"Resubmitted"`

> [accordion] En espera del usuario — "Awaiting User"
>
> **Valor en la API:** `"Awaiting User"`
>
> Se usa en **sesiones de KYB (verificación de empresas)** cuando el paso de Personas clave ha enviado la lista de partes y ha generado sesiones KYC / KYB hijas. La sesión principal espera hasta que **todas las partes obligatorias completen su verificación individual**.
>
> * **Qué hacer:** supervisa los estados de las sesiones KYC hijas. Cuando todas las partes obligatorias terminan (aprobadas, rechazadas o expiradas), la sesión principal vuelve a agregar los resultados automáticamente para obtener su estado final.
> * **El webhook incluye:** la lista actual de partes y los estados de sus sesiones hijas.
> * **Pasa a:** `"Approved"`, `"Declined"`, `"In Review"` (cuando todas las sesiones hijas están en un estado final)
> * **Viene de:** `"In Progress"` (después de enviar el paso de Personas clave)
> * **Nota:** si una sesión KYC hija se reenvía, la sesión principal vuelve a `"Awaiting User"` hasta que se complete la sesión reenviada. Un resultado `"Declined"` en la comprobación de registro KYB tiene prioridad sobre `"Awaiting User"`.

> [accordion] Reenviada — "Resubmitted"
>
> **Valor en la API:** `"Resubmitted"`
>
> Un revisor solicitó que el usuario **repita pasos de verificación concretos** (por ejemplo, volver a fotografiar un documento borroso).
>
> * **Qué hacer:** espera a que el usuario complete los pasos reenviados. El sistema vuelve a evaluar la sesión automáticamente.
> * **El webhook incluye:** el objeto `resubmit_info` con la lista de funciones que se deben repetir y los motivos.
> * **Pasa a:** `"Approved"`, `"Declined"`, `"In Review"`, o `"Abandoned"` si el plazo de la sesión termina antes de que la persona repita los pasos.

> [accordion] Expirada — "Expired"
>
> **Valor en la API:** `"Expired"`
>
> La sesión **caducó antes de que el usuario abriera el enlace de verificación**.
>
> * **Qué hacer:** crea una sesión nueva y envía al usuario un enlace nuevo.
> * **Estado final:** no hay más transiciones.

> [accordion] Abandonada — "Abandoned"
>
> **Valor en la API:** `"Abandoned"`
>
> El usuario **empezó la verificación, pero no la terminó** dentro del plazo permitido.
>
> * **Qué hacer:** envía un recordatorio o crea una sesión nueva.
> * **Sin transiciones automáticas.** Un revisor, o `PATCH /v3/session/{sessionId}/update-status/`, todavía puede cambiarla a `"Approved"`, `"Declined"` o `"Resubmitted"`.

> [accordion] KYC expirado — "Kyc Expired"
>
> **Valor en la API:** `"Kyc Expired"`
>
> El documento verificado durante la sesión **superó su propia fecha de caducidad**. El disparador es esa fecha, no un plazo contado desde la aprobación, y no se envía ningún aviso previo.
>
> * **Qué hacer:** pide al usuario que vuelva a verificarse con una sesión nueva. `status.updated` notifica la transición, y el resultado de la verificación de identidad incluye la advertencia `DOCUMENT_EXPIRED`.
> * **Se controla con:** el **Expiration mode** de ese país y tipo de documento en *ID verification → Additional settings by country & document type*: **Reject expired** (el valor predeterminado) supervisa el documento; con **Allow expired**, la sesión nunca pasa a este estado.
> * **Sin transiciones automáticas.** Un revisor, o `PATCH /v3/session/{sessionId}/update-status/`, todavía puede cambiarla a `"Approved"`, `"Declined"` o `"Resubmitted"`.

***

## Transiciones de estado

| Desde | Hasta | Disparador |
| - | - | - |
| `"Not Started"` | `"In Progress"` | El usuario abre el enlace de verificación |
| `"Not Started"` | `"Expired"` | El TTL de la sesión vence antes de que el usuario abra el enlace |
| `"In Progress"` | `"Approved"` | Se superan todas las comprobaciones automáticas |
| `"In Progress"` | `"Declined"` | Fallan una o más comprobaciones |
| `"In Progress"` | `"In Review"` | Las comprobaciones marcan advertencias que requieren revisión humana |
| `"In Progress"` | `"Awaiting User"` | Se envía el paso de personas clave de KYB; la sesión principal espera a las partes KYC secundarias |
| `"In Progress"` | `"Abandoned"` | El usuario no termina dentro del plazo |
| `"Awaiting User"` | `"Approved"` | Todas las partes KYB requeridas terminan y se superan las comprobaciones agregadas |
| `"Awaiting User"` | `"Declined"` | Se rechaza una parte requerida o falla la comprobación en el registro de empresas de KYB |
| `"Awaiting User"` | `"In Review"` | El resultado agregado de KYB requiere revisión manual |
| `"In Review"` | `"Approved"` | El revisor aprueba manualmente |
| `"In Review"` | `"Declined"` | El revisor rechaza manualmente |
| `"In Review"` | `"Resubmitted"` | El revisor solicita rehacer pasos concretos |
| `"Declined"` | `"Resubmitted"` | El revisor solicita rehacer pasos concretos |
| `"Approved"` | `"Resubmitted"` | El revisor solicita rehacer pasos concretos |
| `"Approved"` | `"Declined"` | Un revisor o la API establece la otra decisión |
| `"Declined"` | `"Approved"` | Un revisor o la API establece la otra decisión |
| `"Abandoned"`, `"Kyc Expired"` | `"Approved"`, `"Declined"`, `"Resubmitted"` | Un revisor o la API decide una sesión que terminó sin una decisión |
| `"Resubmitted"` | `"Abandoned"` | La ventana de la sesión termina antes de que la persona rehaga los pasos |
| `"Resubmitted"` | `"Approved"` | Los pasos reenviados superan todas las comprobaciones |
| `"Resubmitted"` | `"Declined"` | Los pasos reenviados fallan |
| `"Resubmitted"` | `"In Review"` | Los pasos reenviados marcan nuevas advertencias |
| `"Resubmitted"` (KYB secundaria) | `"Awaiting User"` (KYB principal) | La sesión principal vuelve al estado de espera hasta que la secundaria se complete |
| `"Approved"` | `"Kyc Expired"` | Se supera la fecha de caducidad del documento verificado (el modo de caducidad es **Reject expired**) |

### Diagrama del ciclo de vida

```mermaid theme={null}
flowchart LR
    NS["Not Started"] --> IP["In Progress"]
    NS --> EX["Expired"]
    IP --> AP["Approved"]
    IP --> DC["Declined"]
    IP --> IR["In Review"]
    IP --> AU["Awaiting User<br/>(KYB only)"]
    IP --> AB["Abandoned"]
    AU --> AP
    AU --> DC
    AU --> IR
    IR --> AP
    IR --> DC
    IR --> RS["Resubmitted"]
    DC --> RS
    AP --> RS
    AP <--> DC
    AB --> AP
    AB --> DC
    AB --> RS
    KE --> AP
    KE --> DC
    KE --> RS
    RS --> AB
    RS --> AP
    RS --> DC
    RS --> IR
    AP --> KE["Kyc Expired"]
```

***

## Terminales vs. no terminales

| Categoría | Estados | Significado |
| - | - | - |
| **Decidido** | `"Approved"`, `"Declined"`, `"Kyc Expired"` | Las comprobaciones produjeron una decisión y nada la cambia por sí sola, excepto `"Approved"` → `"Kyc Expired"` cuando pasa la fecha de caducidad del documento verificado. Un revisor o el endpoint de actualización de estado todavía pueden cambiar la decisión. |
| **No terminal** | `"Not Started"`, `"In Progress"`, `"Resubmitted"`, `"Awaiting User"` | Siguen activos: a la espera de una acción del usuario, de sesiones secundarias o de procesamiento. |
| **Accionable** | `"In Review"` | Requiere intervención manual de tu equipo. |
| **Inactivo** | `"Expired"`, `"Abandoned"` | Terminó sin una decisión de verificación. `"Expired"` nunca cambia; un revisor todavía puede tomar una decisión sobre una sesión `"Abandoned"`. |

***

## Gestión de estados en tu código

Usa webhooks o la [API de obtención de sesión](https://docs.didit.me/es/sessions-api/retrieve-session.md) para reaccionar a los cambios de estado.

> [!WARNING]
>
> Los estados son **cadenas exactas, que distinguen entre mayúsculas y minúsculas y contienen espacios**. Por ejemplo, `"In Review"` (no `"in_review"` ni `"IN_REVIEW"`). Usa siempre igualdad estricta (`===`) al compararlos.

```javascript theme={null}
// All ten possible status string values (StatusChoices, source of truth):
// "Not Started"  | "In Progress" | "Approved"     | "Declined" |
// "In Review"    | "Resubmitted" | "Awaiting User"|
// "Expired"      | "Abandoned"   | "Kyc Expired"

async function handleWebhook(webhook) {
  const { status, vendor_data: vendorData } = webhook;

  switch (status) {
    case "Not Started":
      // Session created but user hasn't opened the link yet
      break;

    case "In Progress":
      // User is actively completing verification steps
      break;

    case "Approved":
      // All checks passed — grant access
      await db.users.update(vendorData, {
        verified: true,
        verifiedAt: new Date(),
        decision: webhook.decision,
      });
      break;

    case "Declined":
      // Verification failed — notify user
      await db.users.update(vendorData, {
        verificationStatus: "declined",
        declineReasons: webhook.decision?.warnings,
      });
      break;

    case "In Review":
      // Needs manual review by compliance team
      await db.users.update(vendorData, {
        verificationStatus: "pending_review",
      });
      break;

    case "Awaiting User":
      // KYB parent waiting for all child KYC parties to finish
      await db.users.update(vendorData, {
        verificationStatus: "awaiting_kyb_parties",
      });
      break;

    case "Resubmitted":
      // User will redo specific steps
      await db.users.update(vendorData, {
        verificationStatus: "resubmission_pending",
        resubmitInfo: webhook.resubmit_info,
      });
      break;

    case "Abandoned":
      // User started but didn't finish — send reminder
      await sendReminderEmail(vendorData);
      break;

    case "Expired":
    case "Kyc Expired":
      // Session expired — create a new one
      await createNewSession(vendorData);
      break;
  }
}
```

***

## Reenvío

El estado **Resubmitted** permite a tu equipo de cumplimiento dar a los usuarios una segunda oportunidad sin crear una nueva sesión.

**1. El revisor inicia el reenvío**

Desde la consola, abre una sesión `In Review` o `Declined` y haz clic en **Solicitar reenvío**. Selecciona qué pasos deben rehacerse.

**2. Los datos anteriores se archivan**

El sistema restablece las funciones seleccionadas y marca los datos anteriores como `previous_attempt`, con lo que se conserva el registro de auditoría completo.

**3. Se notifica al usuario**

Si hay una dirección de correo electrónico disponible, el usuario recibe un correo electrónico en su idioma con un enlace directo para continuar.

**4. El usuario rehace pasos concretos**

El usuario solo repite los pasos que se marcaron, no toda la verificación.

**5. El sistema vuelve a evaluar**

Una vez completado el proceso, la sesión pasa automáticamente a `"Approved"`, `"Declined"` o `"In Review"`.

### Payload del webhook de reenvío

```json theme={null}
{
  "session_id": "uuid-of-the-session",
  "status": "Resubmitted",
  "resubmit_info": {
    "nodes_to_resubmit": [
      { "node_id": "feature_ocr", "feature": "OCR" },
      { "node_id": "feature_liveness", "feature": "LIVENESS" }
    ],
    "reasons": {
      "feature_ocr": "DOCUMENT_EXPIRED",
      "feature_liveness": "LOW_LIVENESS_SCORE"
    }
  }
}
```

`reasons` asigna a cada `node_id` reenviado el código de advertencia del registro más relevante de ese paso (los mismos códigos que informa la [decisión](https://docs.didit.me/es/reference/data-models.md)), para que puedas asociarlo a tus propios textos. También es el código que la pantalla de reenvío del flujo alojado y el correo de reenvío presentan al usuario en su idioma, excepto en las advertencias que revelarían una señal de análisis o de fraude (duplicados, AML, lista de bloqueo, comprobaciones entre organizaciones, integridad de la ubicación y similares): en esos casos, la persona ve un motivo genérico, y `resubmit_info.reasons` en tu webhook siempre contiene el código real. Un paso sin ninguna advertencia registrada no tiene entrada.

### Qué funciones se pueden reenviar

Cualquier función con un estado no aprobado: **Declined**, **In Review**, **Not Finished**, **Not Started** o **Expired**.

> [!TIP]
>
> Puedes solicitar el reenvío varias veces en la misma sesión. Cada ciclo archiva los datos del intento anterior, lo que te da visibilidad completa del historial de verificación del usuario.

***

## Buenas prácticas

> [card] Supervisa las sesiones en revisión
>
> Configura alertas (por correo electrónico o Slack) en la consola de Didit para recibir avisos cuando haya sesiones que necesiten revisión manual.

> [card] Prioriza el reenvío
>
> Si el problema tiene solución (foto borrosa, cara equivocada del documento), solicita un reenvío en lugar de rechazar la sesión. Así mejoras la tasa de conversión.

> [card] Haz seguimiento de los abandonos
>
> Unas tasas altas de sesiones abandonadas o expiradas pueden indicar fricción en la experiencia de usuario. Plantéate ajustar el TTL de la sesión o mejorar las indicaciones al usuario.

> [card] Controladores idempotentes
>
> Los webhooks pueden reintentarse. Usa `session_id` como clave única para procesar cada cambio de estado una sola vez.

> [!WARNING]
>
> Verifica siempre las firmas de los webhooks antes de procesar los payloads. Didit ofrece tres métodos: `X-Signature`, `X-Signature-V2` (recomendado) y el obsoleto `X-Signature-Simple`, que solo autentica el sobre y nunca el cuerpo de `decision`. Consulta [Webhooks](https://docs.didit.me/es/integration/webhooks.md#verificación-de-firma) para más detalles.


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