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

# SDK Android Kotlin de verificación de identidad: KYC

> SDK nativo de Didit para Android en Kotlin: verificación de identidad, liveness y lectura NFC de e-pasaportes. Desde $0.33 por KYC, $10 gratis/mes.



Prompt de integración del SDK de Android
        Copiar el prompt al portapapeles



      
      

\<pre>

\`Integrate Didit identity verification into my Android app using the native Kotlin SDK.

\## Requirements
\- Android API 23+ (Android 6.0 Marshmallow). ML-based auto-detection (document/face) requires API 24+ and falls back to manual capture below that.
\- Kotlin 1.9+
\- NFC reading requires NFC-capable device hardware

\## Installation

\### Step 1: Add Maven Repository
In settings.gradle.kts:
dependencyResolutionManagement {
repositories {
    google()
    mavenCentral()
    maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
}
}

\### Step 2: Add Dependency
(!) Regarding the version ensure you check the [GitHub repository](https://github.com/didit-protocol/sdk-android) for the latest version.
In app/build.gradle.kts:
dependencies {
implementation("me.didit:didit-sdk:4.9.1")
}

\### Step 3: Add Packaging Exclusion (required to avoid build conflicts)
In the android { } block of app/build.gradle.kts:
android {
packaging {
    resources {
        excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
    }
}
}

\## Permissions (auto-merged from SDK manifest)
\- INTERNET (required) — API communication
\- ACCESS_NETWORK_STATE (required) — Network availability
\- CAMERA (required) — Document scanning and face verification
\- NFC (optional) — Read NFC chips in passports/IDs

Camera and NFC are declared as optional features (android:required="false"), so the app installs on all devices.

\## Initialization (required)
In your Application class:
import me.didit.sdk.DiditSdk

class MyApp : Application() {
override fun onCreate() {
    super.onCreate()
    DiditSdk.initialize(this)
}
}

Register in AndroidManifest.xml:
\<application android:name=".MyApp" ...>

\## Backend: Create Session (your server)
POST https://verification.didit.me/v3/session/
Headers: { "x-api-key": DIDIT_API_KEY, "Content-Type": "application/json" }
Body: { "workflow_id": DIDIT_WORKFLOW_ID, "vendor_data": "user-id" }
Response: { "session_id": "uuid", "session_token": "short-token", "url": "https://verify.didit.me/session/short-token", "status": "Not Started" }
Send session_token to the Android app (never expose DIDIT_API_KEY to the device).

\## Jetpack Compose Integration
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

// Observe SDK state and launch UI when ready
LaunchedEffect(Unit) {
DiditSdk.state.collect { state ->
    when (state) {
        is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(activity)
        is DiditSdkState.Error -> Log.e("Didit", "Error: state.message")
        else -> { /* Loading, Idle, CreatingSession */ }
    }
}
}

// Start verification with session token from backend
import me.didit.sdk.VerificationStatus

fun startVerification(token: String) {
DiditSdk.startVerification(token = token) { result ->
    when (result) {
        is VerificationResult.Completed -> when (result.session.status) {
            VerificationStatus.APPROVED -> { /* grant access */ }
            VerificationStatus.DECLINED -> { /* show retry */ }
            VerificationStatus.PENDING  -> { /* under review */ }
        }
        is VerificationResult.Cancelled -> { /* user cancelled */ }
        is VerificationResult.Failed    -> { /* show error: result.error.message */ }
    }
}
}

\## Result Statuses (VerificationStatus enum; .rawValue gives "Approved" / "Pending" / "Declined")
\- VerificationStatus.APPROVED — user identity verified, grant access
\- VerificationStatus.DECLINED — verification failed, show retry or contact support
\- VerificationStatus.PENDING  — needs manual review by your compliance team

\## Full Verification Results
The SDK only returns the status. Full decision data (document fields, face match scores, AML hits, etc.) arrives via webhook to your backend.
Set up webhooks: https://docs.didit.me/integration/webhooks

\## Rate Limits (session creation)
\- 600 session-create requests / minute per x-api-key (see https://docs.didit.me/integration/rate-limiting)
\- On 429, retry honouring Retry-After / X-RateLimit-* headers

\## Environment Variables (backend only — never expose in the Android app)
\- DIDIT_API_KEY — from Didit Console > API & Webhooks
\- DIDIT_WORKFLOW_ID — from Didit Console > Workflows

\## Docs
\- Android SDK: https://docs.didit.me/integration/native-sdks/android-sdk
\- GitHub: https://github.com/didit-protocol/sdk-android
\- Webhooks: https://docs.didit.me/integration/webhooks
\- API Reference: https://docs.didit.me/api-reference/overview`

\</pre>



      
      

Pegar en

Un SDK de Android ligero y controlado desde el servidor para la verificación de identidad, que requiere una configuración mínima.> [card] [Repositorio de GitHub](https://github.com/didit-protocol/sdk-android)
>
> Consulta el código fuente y los ejemplos en GitHub> [!NOTE]
>
> ### **SDK nativo**: Este es el enfoque recomendado para apps de Android. Los SDK nativos ofrecen la mejor experiencia de usuario, un manejo optimizado de la cámara y compatibilidad completa con NFC.***## Requisitos| Requisito | Versión mínima |
| - | - |
| API de Android | 23+ (Android 6.0 Marshmallow). La detección automática con ML requiere API 24+ (ver más abajo). |
| Kotlin | 1.9+ |
| Jetpack Compose | Incluido como dependencia transitiva |> [!NOTE]
>
> **Disponibilidad de funciones según el nivel de API**: La detección automática de documentos y rostros requiere API 24+ (con el runtime de ML incluido o con el runtime de Google Play services; consulta las variantes del SDK). En dispositivos con API 23, el SDK recurre a la captura manual con un botón de captura temporizado. Todas las demás funciones están disponibles en todo el rango de API 23+.> [!NOTE]
>
> **El consentimiento biométrico requiere la versión nativa 4.10.0 o posterior.** Para las personas amparadas por las leyes de Illinois, Texas o Colorado, Didit puede solicitar un [consentimiento biométrico](https://docs.didit.me/es/getting-started/biometric-consent.md) explícito antes de la primera captura facial. El SDK de Android 4.10.0 y posteriores muestran ese paso. Las versiones anteriores no pueden mostrarlo: sus sesiones se ejecutan como hasta ahora y la decisión indica que el consentimiento no se recopiló (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). Actualiza el SDK si verificas a personas de esos estados.***## Instalación### Paso 1: Añade el repositorioAñade el repositorio Maven de Didit al bloque `repositories` de tu `settings.gradle.kts`:```kotlin theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}
```O, si usas `settings.gradle` (Groovy):```groovy theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}
```### Paso 2: Añade la dependenciaAñade la dependencia del SDK al `build.gradle.kts` de tu app:
(!) En cuanto a la versión, asegúrate de consultar el [repositorio de GitHub](https://github.com/didit-protocol/sdk-android) para conocer la versión más reciente.```kotlin theme={null}
dependencies {
    implementation("me.didit:didit-sdk:4.9.1")
}
```O, si usas `build.gradle` (Groovy):```groovy theme={null}
dependencies {
    implementation "me.didit:didit-sdk:4.9.1"
}
```#### Variantes del SDKEl SDK de Android se distribuye como **cinco artefactos independientes**, de modo que tu app solo asume el coste en tamaño binario de las
funciones que utiliza. `me.didit:didit-sdk`, el de arriba, es el paquete completo. Elige exactamente uno, con una única
excepción: los dos artefactos de detección automática pueden instalarse juntos, como se describe más abajo:| Artefacto | Detección automática (ML) | Lectura del chip NFC | Cuándo usarlo |
| - | :-: | :-: | - |
| `me.didit:didit-sdk-core` | – | – | compilación más pequeña; solo captura manual de documentos |
| `me.didit:didit-sdk-autodetection` | ✓ | – | captura automática, sin lectura del chip del pasaporte o documento de identidad |
| `me.didit:didit-sdk-autodetection-play` | ✓ | – | captura automática mediante el runtime de ML de Play services; \~9.85 MB menos instalados por dispositivo (arm64) que con el runtime incluido (ver más abajo) |
| `me.didit:didit-sdk-nfc` | – | ✓ | lectura del chip sin el runtime de ML para la captura automática |
| `me.didit:didit-sdk` | ✓ | ✓ | todas las funciones (paquete completo) |##### Runtime de ML más ligero mediante Google Play services (opcional, desde 4.7.0)`me.didit:didit-sdk-autodetection-play` ofrece la misma captura automática de documentos y rostros que
`didit-sdk-autodetection`, pero ejecuta la inferencia en el runtime de ML que Google Play services ya
proporciona en el dispositivo, en lugar de incluir uno en tu APK.
El comportamiento de la detección es idéntico (ambos motores se compararon fotograma a fotograma entre sí
en una matriz de dispositivos físicos antes del lanzamiento) y la inferencia suele ser más rápida con el runtime de Play.Para activarlo, sustituye el artefacto:```kotlin theme={null}
// before
implementation("me.didit:didit-sdk-autodetection:4.9.1")
// after
implementation("me.didit:didit-sdk-autodetection-play:4.9.1")
```Qué cambia:- **Tamaño**: unos **9.85 MB menos de código nativo instalado por dispositivo (arm64)**, porque el runtime de ML
  ya no está dentro de tu app. (Una comparación con un APK universal sin minificar y con 4 ABI muestra una
  diferencia mayor, de \~43 MB, pero esa cifra cuenta varias veces arquitecturas que ningún dispositivo instala a la vez;
  la cifra por dispositivo indicada arriba es la que realmente perciben tus usuarios).
- **Requisito**: Google Play services. En dispositivos que no lo tienen (por ejemplo, dispositivos Huawei
  sin GMS), o si el runtime de Play no se inicializa, el SDK recurre automáticamente a una alternativa:
  al runtime incluido cuando también está instalado `didit-sdk-autodetection`, o a la captura manual
  en caso contrario. Nunca falla porque un runtime no esté disponible.
- **Elección de cobertura**: distribuye solo `-play` para conseguir la app más pequeña (los usuarios sin GMS tendrán captura
  manual), o distribuye ambos artefactos para mantener la captura automática con ML en dispositivos sin GMS con el
  tamaño original.Ambos artefactos requieren `didit-sdk-core` 4.7.0 o posterior.> [!NOTE]
>
> `didit-sdk-autodetection-play` es opcional por ahora. Didit hace seguimiento de su rendimiento en producción frente
> al runtime incluido durante un ciclo de versiones tras su lanzamiento; cuando esos datos confirmen la paridad, se prevé que el
> artefacto de Play pase a ser la forma recomendada de instalar la detección automática, y
> `didit-sdk-autodetection` (incluido) sigue siendo la recomendación predeterminada hasta entonces.Desde `4.6.0`, la firma nativa con wallets mediante WalletConnect se distribuye como un complemento opcional propio, `me.didit:didit-sdk-wallet`.
El paquete completo `me.didit:didit-sdk` ya lo incluye, así que no cambia nada si instalas el paquete completo.
Si usas uno de los artefactos más ligeros y quieres que la confirmación de propiedad de la wallet se ejecute de forma nativa dentro de tu app, añade `me.didit:didit-sdk-wallet` junto a él; sin el complemento, el SDK completa la confirmación de propiedad de la wallet mediante un flujo seguro en el navegador, así que la función sigue funcionando en ambos casos.
Sacar WalletConnect de `didit-sdk-core` también eliminó varios megabytes de dependencias de wallet de todas las compilaciones que no las necesitan.Todos los artefactos se publican con la misma versión, así que mantenlos en `4.9.1`.#### Cómo mantener reducido el tamaño de descargaLos modelos de detección que usa la captura automática se descargan en tiempo de ejecución y se almacenan en caché, por lo que nunca cuentan para el tamaño de tu app.
Lo que la captura automática añade a tu app es la biblioteca nativa del runtime de ML, y ese coste es por arquitectura de CPU: aproximadamente 10 MB para `arm64-v8a`, 7 MB para `armeabi-v7a` y 13 MB para cada una de las dos arquitecturas x86 de emulador.Para asumir ese coste una sola vez:1) **Publica un Android App Bundle (AAB).** Google Play entrega solo la arquitectura y los idiomas propios del dispositivo, así que un teléfono arm64 instala unos 10 MB de código nativo (unos 4 MB de descarga comprimida). En cambio, un APK universal empaqueta las cuatro arquitecturas (más de 40 MB), que es la causa más habitual de mediciones de tamaño inesperadamente grandes.

2) **Si distribuyes un único APK** y tu público usa teléfonos y tabletas ARM, restringe las arquitecturas incluidas:

   ```kotlin theme={null}
   android {
       defaultConfig {
           ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
       }
   }
   ```

   Conserva todas las ABI que realmente usan tus usuarios: añade `x86_64` si te diriges a Chromebooks u otros dispositivos x86, o publica APK divididos por ABI para que ningún dispositivo pierda compatibilidad.

3) **Activa R8**: `isMinifyEnabled = true` e `isShrinkResources = true` en tu tipo de compilación de release (`minifyEnabled true` / `shrinkResources true` si usas `build.gradle` en Groovy). El SDK incluye sus propias reglas de consumidor, por lo que el código del SDK que no se usa se elimina sin configuración adicional.

4) **Limita los idiomas incluidos** con `resConfigs(...)` si no necesitas las 48 configuraciones regionales del SDK en una compilación APK; en Google Play, la división por idioma de los AAB se encarga de esto automáticamente.### Paso 3: Añade la exclusión de empaquetadoAñade esto al bloque `android` de tu app para evitar conflictos de compilación:```kotlin theme={null}
android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}
```¡Listo! Gradle resolverá automáticamente todas las dependencias transitivas.***## PermisosEl SDK requiere los siguientes permisos. Están declarados en el `AndroidManifest.xml` del SDK y se fusionarán automáticamente en el manifiesto de tu aplicación:| Permiso | AAR de origen | Descripción | Obligatorio |
| - | - | - | - |
| `INTERNET` | `didit-sdk-core` | Acceso a la red para la comunicación con la API | Sí |
| `ACCESS_NETWORK_STATE` | `didit-sdk-core` | Detectar la disponibilidad de la red | Sí |
| `CAMERA` | `didit-sdk-core` | Escaneo de documentos y verificación facial | Sí |
| `NFC` | `didit-sdk-nfc` | Leer chips NFC de pasaportes y documentos de identidad | Se fusiona automáticamente desde `didit-sdk-nfc` (dependencia transitiva de `me.didit:didit-sdk`) |### Características de cámara y NFCEl SDK declara `android.hardware.camera` y `android.hardware.nfc` como características opcionales (`android:required="false"`). Así tu aplicación puede instalarse en dispositivos sin cámara o sin hardware NFC, y el SDK gestionará correctamente la ausencia de hardware en tiempo de ejecución.***## Inicio rápido### Paso 1: Inicializa el SDKInicializa el SDK en el `Application.onCreate()` de tu aplicación:```kotlin theme={null}
import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}
```### Paso 2: Inicia la verificación y gestiona los resultados```kotlin theme={null}
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state to launch UI when ready
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Loading, Idle, CreatingSession */ }
                }
            }
        }
    }

    private fun startVerification() {
        // Method 1: UniLink (no backend required)
        DiditSdk.startVerification(
            workflowId = "your-workflow-id",
            vendorData = "user-123"
        ) { result ->
            handleResult(result)
        }

        // Method 2: Backend Session (recommended for production)
        // DiditSdk.startVerification(
        //     token = "your-session-token"
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                Log.d("Didit", "Session: ${result.session.sessionId}")
                Log.d("Didit", "Status: ${result.session.status}")
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "User cancelled")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Failed: ${result.error.message}")
            }
        }
    }
}
```***## Métodos de integraciónEl SDK admite dos métodos de integración:### Método 1: UniLink (el más sencillo)No requiere backend. El SDK crea la sesión directamente con el ID de tu flujo de verificación (workflow) de Didit Console. Solo admite `vendorData`.```kotlin theme={null}
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"
) { result ->
    handleResult(result)
}
```### Método 2: Sesión desde el backend (recomendado para producción)Tu backend crea la sesión mediante la [API de creación de sesiones de verificación](https://docs.didit.me/es/sessions-api/create-session.md) (`POST /v3/session/`) con soporte completo de parámetros (`contact_details`, `expected_details`, `metadata`, `callback`, etc.) y después pasa el `session_token` al SDK.```kotlin theme={null}
// Your backend creates a session and returns the token
val sessionToken = yourBackend.createVerificationSession(userId = currentUser.id)

// Pass the token to the SDK
DiditSdk.startVerification(
    token = sessionToken
) { result ->
    handleResult(result)
}
```Este enfoque te da control total para:- Asociar sesiones con tus usuarios (`vendor_data`)
- Definir metadatos personalizados
- Configurar callbacks por sesión
- Proporcionar datos de contacto y datos esperados para la validación cruzada***## ConfiguraciónPersonaliza el comportamiento del SDK:```kotlin theme={null}
import me.didit.sdk.Configuration
import me.didit.sdk.core.localization.SupportedLanguage

val configuration = Configuration(
    languageLocale = SupportedLanguage.SPANISH,  // Force Spanish language
    showLanguageSelector = true,                  // Let the user change language
    fontFamily = "my_custom_font",                // Custom font (must be in res/font/)
    loggingEnabled = true                         // Enable debug logging
)

DiditSdk.startVerification(
    token = "your-session-token",
    configuration = configuration
) { result ->
    handleResult(result)
}
```### Opciones de configuración| Propiedad | Tipo | Valor predeterminado | Descripción |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | Configuración regional del dispositivo | Fuerza un idioma específico |
| `showLanguageSelector` | `Boolean` | `false` | Muestra el selector de idioma de estilo web en la pantalla de bienvenida |
| `fontFamily` | `String?` | Fuente del sistema | Nombre del recurso de fuente personalizada (de `res/font/`) |
| `loggingEnabled` | `Boolean` | `false` | Activa el registro de depuración del SDK |
| `showCloseButton` | `Boolean` | `true` | Muestra el botón de cerrar (X) en las pantallas de los pasos de verificación |
| `showExitConfirmation` | `Boolean` | `true` | Muestra un cuadro de diálogo de confirmación cuando el usuario intenta salir |
| `closeOnComplete` | `Boolean` | `false` | Cierra automáticamente la interfaz de verificación al finalizar (equivalente en el Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `CameraLens.BACK` | Lente que se usa al abrir la pantalla de captura del documento |
| `defaultLivenessCamera` | `CameraLens` | `CameraLens.FRONT` | Lente que se usa al abrir la pantalla de captura facial (prueba de vida) |
| `showDocumentCameraSwitchButton` | `Boolean` | `true` | Muestra el selector de cámara durante la captura en la pantalla de captura del documento |
| `showLivenessCameraSwitchButton` | `Boolean` | `true` | Muestra el selector de cámara durante la captura en la pantalla de captura facial |### Opciones de cámaraLas opciones de cámara coinciden con las [opciones de cámara del Web SDK](https://docs.didit.me/es/integration/web-sdks/javascript-sdk.md#opciones-de-cámara).
Cada lente es `CameraLens.FRONT` o `CameraLens.BACK`.
Si el dispositivo no tiene la lente solicitada, el SDK usa la primera cámara disponible.
El selector de cámara también se oculta en los dispositivos que solo tienen una cámara.
Establece una opción del selector en `false` para restringir al usuario a la lente predeterminada de ese paso.```kotlin theme={null}
val configuration = Configuration(
    defaultLivenessCamera = CameraLens.BACK,
    showLivenessCameraSwitchButton = false
)
```> [!NOTE]
>
> Las opciones `showLanguageSelector`, `showCloseButton`, `showExitConfirmation` y `closeOnComplete` coinciden con la `DiditSdkConfiguration` del Web SDK. Las opciones exclusivas de móvil `languageLocale` y `fontFamily` existen porque el SDK móvil renderiza de forma nativa toda la interfaz de verificación (a diferencia del Web SDK, que delega en el frontend alojado dentro de un iframe).> [!NOTE]
>
> **Temas y colores**: los colores, los fondos y la configuración de la pantalla de introducción se definen en la [configuración de marca blanca](https://business.didit.me) de Didit Console, no en la configuración del SDK. Así se garantiza una imagen de marca coherente en todas las plataformas.***## Idiomas compatiblesEl SDK admite **54 idiomas**. Si no se especifica ningún idioma, el SDK usa la configuración regional del dispositivo, con el inglés como idioma alternativo.```kotlin theme={null}
// Use device locale (default)
val config = Configuration()

// Force specific language
val config = Configuration(languageLocale = SupportedLanguage.FRENCH)

// Let the user change language on the welcome screen
val config = Configuration(showLanguageSelector = true)
```**[Ver todos los idiomas compatibles →](https://docs.didit.me/es/integration/supported-languages.md)*****## Opciones avanzadasPara los parámetros avanzados de sesión (`contact_details`, `expected_details`, `metadata`, `callback`), usa el método **Backend Session**. Tu backend invoca la [API de creación de sesiones de verificación](https://docs.didit.me/es/sessions-api/create-session.md) con todos los parámetros y después pasa el `session_token` al SDK.***## Gestión de resultadosLa clase sellada `VerificationResult` proporciona el resultado de la verificación:### Casos de resultado| Caso | Descripción |
| - | - |
| `Completed(session)` | El flujo de verificación ha finalizado (consulta `session.status` para conocer el resultado) |
| `Cancelled(session)` | El usuario canceló el flujo de verificación |
| `Failed(error, session)` | Se produjo un error durante la verificación |### Propiedades de SessionData| Propiedad | Tipo | Descripción |
| - | - | - |
| `sessionId` | `String` | Identificador único de la sesión |
| `status` | `VerificationStatus` | `APPROVED`, `PENDING` o `DECLINED` |### Tipos de errorTodos los errores son subclases selladas de `me.didit.sdk.VerificationError`:| Error | Descripción |
| - | - |
| `SessionExpired` | La sesión ha expirado |
| `NetworkError` | Problema de conectividad de red |
| `CameraAccessDenied` | No se concedió el permiso de cámara |
| `NotInitialized` | El SDK no está inicializado: llama primero a `DiditSdk.initialize(context)` |
| `ApiError` | El backend devolvió una respuesta de error |
| `RetryBlocked` | No se puede reintentar la verificación (p. ej., se alcanzó el número máximo de intentos) |
| `Unknown(message)` | Otro error, con mensaje |### Pérdida de conexiónSi el dispositivo pierde la conexión durante la verificación, el SDK muestra una pantalla de "Sin conexión a internet" en lugar de dejar un paso en estado de carga.
Sigue comprobando en segundo plano y cierra la pantalla por sí solo en cuanto Didit vuelve a estar disponible, y el usuario continúa desde el paso en el que estaba.
La pantalla ofrece **Intentar de nuevo** y, cuando `showCloseButton` es `true` (el valor predeterminado), **Salir de la verificación**.
Al salir, la verificación termina con `VerificationResult.Failed(error = VerificationError.NetworkError, session = ...)`, de modo que tu aplicación sabe que el usuario salió debido a un problema de conexión.### Ejemplo completo de gestión de resultados```kotlin theme={null}
DiditSdk.startVerification(token = "your-token") { result ->
    when (result) {
        is VerificationResult.Completed -> {
            when (result.session.status) {
                VerificationStatus.APPROVED -> {
                    Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    // User is verified - grant access
                }
                VerificationStatus.PENDING -> {
                    Log.d("Didit", "Under review. Session: ${result.session.sessionId}")
                    // Show "verification in progress" UI
                }
                VerificationStatus.DECLINED -> {
                    Log.d("Didit", "Declined. Session: ${result.session.sessionId}")
                    // Handle declined verification
                }
            }
        }
        is VerificationResult.Cancelled -> {
            Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            // User chose to cancel - maybe show retry option
        }
        is VerificationResult.Failed -> {
            Log.e("Didit", "Error: ${result.error.message}")
            // Handle error - show retry or contact support
        }
    }
}
```***## Observación del estado del SDKPuedes observar el estado del SDK para crear una interfaz de carga personalizada:```kotlin theme={null}
lifecycleScope.launch {
    DiditSdk.state.collect { state ->
        when (state) {
            is DiditSdkState.Idle -> {
                // Ready to start verification
            }
            is DiditSdkState.CreatingSession -> {
                // Show "Creating session..." progress
            }
            is DiditSdkState.Loading -> {
                // Show loading indicator
            }
            is DiditSdkState.Ready -> {
                // Verification UI is ready - launch it
                DiditSdk.launchVerificationUI(this@MainActivity)
            }
            is DiditSdkState.Error -> {
                // Show error message
                Log.e("Didit", "Error: ${state.message}")
            }
        }
    }
}
```***## ProGuard / R8El SDK incluye sus propias reglas de ProGuard de consumidor. No se necesita ninguna configuración adicional.Si usas el modo completo de R8, es posible que tengas que añadir esto a tu `gradle.properties`:```properties theme={null}
android.enableR8.fullMode=false
```***## Ejemplo de principio a fin (sesión en el backend → SDK de Android → resultado)Este patrón es la integración lista para producción. Tu backend crea la sesión, tu aplicación Android recibe el `session_token` y el SDK ejecuta el flujo.### 1. Backend: crear la sesión```ts theme={null}
// Node.js / Express example. Run on your server. NEVER ship DIDIT_API_KEY to the device.
import express from "express";

const app = express();
app.use(express.json());

app.post("/api/verification/start", async (req, res) => {
  const response = await fetch("https://verification.didit.me/v3/session/", {
    method: "POST",
    headers: {
      "x-api-key": process.env.DIDIT_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      workflow_id: process.env.DIDIT_WORKFLOW_ID,
      vendor_data: req.body.userId, // your stable user id
    }),
  });

  if (!response.ok) {
    return res.status(500).json({ error: `Didit ${response.status}` });
  }

  const { session_id, session_token } = await response.json();
  // Persist session_id <-> userId so you can match the webhook later.
  res.json({ session_id, session_token });
});
```### 2. Android: intercambiar el token e iniciar el SDK```kotlin theme={null}
import android.app.Activity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.didit.sdk.DiditSdk
import me.didit.sdk.VerificationResult
import me.didit.sdk.VerificationStatus
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.MediaType.Companion.toMediaType
import org.json.JSONObject

class VerificationFlow(private val activity: ComponentActivity) {
    private val http = OkHttpClient()
    private val json = "application/json".toMediaType()

    fun start(userId: String) {
        activity.lifecycleScope.launch {
            val token = withContext(Dispatchers.IO) {
                val body = JSONObject().put("userId", userId).toString().toRequestBody(json)
                val req = Request.Builder()
                    .url("https://your-backend.example.com/api/verification/start")
                    .post(body)
                    .build()
                http.newCall(req).execute().use { resp ->
                    JSONObject(resp.body!!.string()).getString("session_token")
                }
            }

            DiditSdk.startVerification(token = token) { result ->
                when (result) {
                    is VerificationResult.Completed -> when (result.session.status) {
                        VerificationStatus.APPROVED -> { /* optimistic UI; rely on webhook for source of truth */ }
                        VerificationStatus.PENDING  -> { /* show "under review" */ }
                        VerificationStatus.DECLINED -> { /* show retry/contact support */ }
                    }
                    is VerificationResult.Cancelled -> { /* user cancelled */ }
                    is VerificationResult.Failed    -> { /* show error: result.error.message */ }
                }
            }
        }
    }
}
```### 3. Backend: recibir la decisión final mediante webhookEl resultado del SDK resulta práctico para dar feedback en la interfaz, pero el resultado que prevalece llega mediante webhook. Consulta la [guía de webhooks](https://docs.didit.me/es/integration/webhooks.md) para la verificación HMAC.```ts theme={null}
app.post("/api/webhooks/didit", express.raw({ type: "application/json" }), (req, res) => {
  // 1. Verify the X-Signature header (see Webhooks docs)
  // 2. Parse the body
  const event = JSON.parse(req.body.toString());
  if (event.webhook_type === "status.updated") {
    // event.session_id, event.status ("Approved" | "Declined" | "In Review" | ...)
    // Look up the user by session_id and update their verification state.
  }
  res.sendStatus(200);
});
```***## Ejemplo completo```kotlin theme={null}
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import me.didit.sdk.Configuration
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult
import me.didit.sdk.VerificationStatus
import me.didit.sdk.core.localization.SupportedLanguage

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Idle, Loading, CreatingSession */ }
                }
            }
        }
    }

    fun startVerification() {
        val config = Configuration(
            languageLocale = SupportedLanguage.ENGLISH,
            loggingEnabled = true
        )

        // Method 1: UniLink (no backend required)
        DiditSdk.startVerification(
            workflowId = "your-workflow-id",
            vendorData = "user-123",
            configuration = config
        ) { result ->
            handleResult(result)
        }

        // Method 2: Backend Session (recommended for production)
        // DiditSdk.startVerification(
        //     token = "your-session-token",
        //     configuration = config
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                when (result.session.status) {
                    VerificationStatus.APPROVED -> {
                        Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    }
                    VerificationStatus.PENDING -> {
                        Log.d("Didit", "Under review")
                    }
                    VerificationStatus.DECLINED -> {
                        Log.d("Didit", "Declined")
                    }
                }
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Error: ${result.error.message}")
            }
        }
    }
}
```***


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