> ## 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 per la Verifica dell'identità (KYC)

> SDK Android nativo in Kotlin di Didit per verifica dell'identità, liveness e NFC. Da $0.33 per KYC completo, $10 gratis al mese, senza contratti.



Prompt di integrazione SDK Android
        Copia il prompt negli appunti



      
      

\<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.13.2")
}

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



      
      

Incolla in

Un SDK Android leggero e guidato dal server per la verifica dell'identità, che richiede una configurazione minima.> [card] [Repository GitHub](https://github.com/didit-protocol/sdk-android)
>
> Visualizza il codice sorgente e gli esempi su GitHub> [!NOTE]
>
> ### **SDK nativo**: è il metodo consigliato per le app Android. Gli SDK nativi offrono la migliore esperienza utente, una gestione ottimizzata della fotocamera e il supporto NFC completo.***## Requisiti| Requisito | Versione minima |
| - | - |
| API Android | 23+ (Android 6.0 Marshmallow). Il rilevamento automatico ML richiede API 24+ (vedi sotto). |
| Kotlin | 1.9+ |
| Jetpack Compose | Incluso come dipendenza transitiva |> [!NOTE]
>
> **Disponibilità delle funzionalità per livello API**: il rilevamento automatico di documenti e volti richiede API 24+ (rilevatori leggeri di Didit, inclusi in `didit-sdk-core`). Sui dispositivi API 23 l'SDK ripiega sull'acquisizione manuale con un pulsante di scatto a tempo. Tutte le altre funzionalità funzionano sull'intero intervallo API 23+.> [!NOTE]
>
> **Il consenso biometrico richiede la versione nativa 4.10.0 o successiva.** Per le persone coperte dalla normativa dell'Illinois, del Texas o del Colorado, Didit può chiedere un [consenso biometrico](https://docs.didit.me/it/getting-started/biometric-consent.md) esplicito prima della prima acquisizione del volto. L'SDK Android 4.10.0 e le versioni successive mostrano questo passaggio. Le versioni precedenti non possono mostrarlo: le loro sessioni proseguono come prima e la decisione riporta il consenso come non raccolto (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). Esegui l'aggiornamento se verifichi persone in questi stati.***## Installazione### Passaggio 1: aggiungi il repositoryAggiungi il repository Maven di Didit al blocco `repositories` del tuo `settings.gradle.kts`:```kotlin theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}
```Se usi `settings.gradle` (Groovy):```groovy theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}
```### Passaggio 2: aggiungi la dipendenzaAggiungi la dipendenza dell'SDK al file `build.gradle.kts` della tua app:
(!) Per la versione, controlla il [repository GitHub](https://github.com/didit-protocol/sdk-android) per l'ultima release disponibile.```kotlin theme={null}
dependencies {
    implementation("me.didit:didit-sdk:4.13.2")
}
```Se usi `build.gradle` (Groovy):```groovy theme={null}
dependencies {
    implementation "me.didit:didit-sdk:4.13.2"
}
```#### Varianti dell'SDKL'SDK Android è distribuito come artefatti separati, quindi la tua app paga in termini di dimensioni del binario solo per le funzionalità che usa. `me.didit:didit-sdk` qui sopra è il bundle completo. Scegli quello più adatto alla tua app:| Artefatto | Rilevamento automatico (ML) | Lettura del chip NFC | Quando usarlo |
| - | :-: | :-: | - |
| `me.didit:didit-sdk-core` | ✓ | – | build più leggera; cattura automatica tramite i rilevatori di Didit, senza lettura del chip di passaporti o documenti |
| `me.didit:didit-sdk-autodetection` | ✓ | – | deprecato e vuoto dalla versione 4.11.0; dipende solo da `didit-sdk-core`, quindi usa `didit-sdk-core` al suo posto |
| `me.didit:didit-sdk-nfc` | ✓ | ✓ | lettura del chip in aggiunta a `didit-sdk-core` |
| `me.didit:didit-sdk` | ✓ | ✓ | tutte le funzionalità (bundle completo) |A partire dalla versione `4.6.0`, la firma del wallet nativa con WalletConnect è distribuita come add-on opzionale separato, `me.didit:didit-sdk-wallet`.
Il bundle completo `me.didit:didit-sdk` lo include già, quindi se installi il bundle non cambia nulla.
Se usi uno degli artefatti più leggeri e vuoi che la conferma della proprietà del wallet avvenga in modo nativo all'interno della tua app, aggiungi `me.didit:didit-sdk-wallet` accanto ad esso; senza l'add-on, l'SDK completa la verifica della proprietà del wallet tramite un flusso sicuro nel browser, quindi la funzionalità continua a funzionare in entrambi i casi.
Spostare WalletConnect fuori da `didit-sdk-core` ha inoltre eliminato diversi megabyte di dipendenze dei wallet da ogni build che non ne ha bisogno.Tutti gli artefatti sono pubblicati con la stessa versione, quindi mantienili alla versione `4.13.2`.#### Come mantenere piccolo il downloadI modelli di rilevamento usati per la cattura automatica vengono scaricati a runtime e memorizzati nella cache, quindi non incidono mai sulla dimensione della tua app.
Ciò che la cattura automatica aggiunge alla tua app è la libreria nativa del runtime ML, e questo costo dipende dall'architettura della CPU: circa 10 MB per `arm64-v8a`, 7 MB per `armeabi-v7a` e 13 MB per ciascuna delle due architetture x86 degli emulatori.Per pagare questo costo una sola volta:1) **Pubblica un Android App Bundle (AAB).** Google Play distribuisce solo l'architettura e le lingue del dispositivo, quindi un telefono arm64 installa circa 10 MB di codice nativo (circa 4 MB di download compresso). Un APK universale invece include tutte e quattro le architetture, oltre 40 MB, che è la causa più comune di misurazioni di dimensione inaspettatamente elevate.

2) **Se distribuisci un singolo APK** e il tuo pubblico usa telefoni e tablet ARM, limita le architetture incluse:

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

   Mantieni tutti gli ABI che i tuoi utenti usano davvero: aggiungi `x86_64` se punti a Chromebook o altri dispositivi x86, oppure pubblica split APK per ABI in modo che nessun dispositivo perda il supporto.

3) **Abilita R8**: imposta `isMinifyEnabled = true` e `isShrinkResources = true` nel tipo di build di release (`minifyEnabled true` / `shrinkResources true` se usi `build.gradle` in Groovy). L'SDK include le proprie regole consumer, quindi il codice dell'SDK non utilizzato viene rimosso senza alcuna configurazione aggiuntiva.

4) **Limita le lingue incluse** con `resConfigs(...)` se non ti servono tutte le 48 lingue dell'SDK in una build APK; gli split per lingua dell'AAB lo gestiscono automaticamente su Google Play.### Passaggio 3: aggiungi l'esclusione del packagingAggiungi questo al blocco `android` della tua app per evitare conflitti di build:```kotlin theme={null}
android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}
```Ecco fatto! Gradle risolverà automaticamente tutte le dipendenze transitive.***## PermessiL'SDK richiede i seguenti permessi. Sono dichiarati nel file `AndroidManifest.xml` dell'SDK e verranno uniti automaticamente al manifest della tua app:| Permesso | AAR di origine | Descrizione | Obbligatorio |
| - | - | - | - |
| `INTERNET` | `didit-sdk-core` | Accesso alla rete per la comunicazione con le API | Sì |
| `ACCESS_NETWORK_STATE` | `didit-sdk-core` | Rilevamento della disponibilità di rete | Sì |
| `CAMERA` | `didit-sdk-core` | Scansione dei documenti e verifica del volto | Sì |
| `NFC` | `didit-sdk-nfc` | Lettura dei chip NFC di passaporti e carte d'identità | Unito automaticamente da `didit-sdk-nfc` (dipendenza transitiva di `me.didit:didit-sdk`) |### Funzionalità di fotocamera e NFCL'SDK dichiara `android.hardware.camera` e `android.hardware.nfc` come funzionalità opzionali (`android:required="false"`). In questo modo la tua app può essere installata su dispositivi senza fotocamera o hardware NFC: l'SDK gestisce correttamente l'assenza dell'hardware durante l'esecuzione.***## Avvio rapido### Passaggio 1: inizializza l'SDKInizializza l'SDK in `Application.onCreate()`:```kotlin theme={null}
import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}
```### Passaggio 2: avvia la verifica e gestisci i risultati```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}")
            }
        }
    }
}
```***## Metodi di integrazioneL'SDK supporta due metodi di integrazione:### Metodo 1: UniLink (il più semplice)Non richiede un backend. L'SDK crea la sessione direttamente usando l'ID del tuo workflow dalla Didit Console. È limitato al solo `vendorData`.```kotlin theme={null}
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"
) { result ->
    handleResult(result)
}
```### Metodo 2: sessione backend (consigliato per la produzione)Il tuo backend crea la sessione tramite l'[API per la creazione della sessione di verifica](https://docs.didit.me/it/sessions-api/create-session.md) (`POST /v3/session/`), con supporto completo dei parametri (`contact_details`, `expected_details`, `metadata`, `callback` e altri), quindi passa il `session_token` all'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)
}
```Questo approccio ti offre il pieno controllo su:- Associazione delle sessioni ai tuoi utenti (`vendor_data`)
- Impostazione di metadati personalizzati
- Configurazione dei callback per sessione
- Fornitura dei dettagli di contatto e dei dettagli attesi per la validazione incrociata***## ConfigurazionePersonalizza il comportamento dell'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)
}
```### Opzioni di configurazione| Proprietà | Tipo | Predefinito | Descrizione |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | Lingua del dispositivo | Forza una lingua specifica |
| `showLanguageSelector` | `Boolean` | `false` | Mostra il selettore della lingua in stile web nella schermata di benvenuto |
| `fontFamily` | `String?` | Font di sistema | Nome della risorsa del font personalizzato (da `res/font/`) |
| `loggingEnabled` | `Boolean` | `false` | Abilita il logging di debug dell'SDK |
| `showCloseButton` | `Boolean` | `true` | Mostra il pulsante di chiusura (X) nelle schermate dei passaggi di verifica |
| `showExitConfirmation` | `Boolean` | `true` | Mostra una finestra di conferma quando l'utente tenta di uscire |
| `closeOnComplete` | `Boolean` | `false` | Chiude automaticamente l'interfaccia di verifica al completamento (equivalente nel Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `CameraLens.BACK` | Obiettivo usato all'apertura della schermata di acquisizione del documento |
| `defaultLivenessCamera` | `CameraLens` | `CameraLens.FRONT` | Obiettivo usato all'apertura della schermata di acquisizione del volto per il rilevamento della vitalità |
| `showDocumentCameraSwitchButton` | `Boolean` | `true` | Mostra il pulsante per cambiare fotocamera nella schermata di acquisizione del documento |
| `showLivenessCameraSwitchButton` | `Boolean` | `true` | Mostra il pulsante per cambiare fotocamera nella schermata di acquisizione del volto |### Opzioni della fotocameraLe opzioni della fotocamera corrispondono alle [opzioni della fotocamera del Web SDK](https://docs.didit.me/it/integration/web-sdks/javascript-sdk.md#opzioni-della-fotocamera).
Ogni obiettivo è `CameraLens.FRONT` o `CameraLens.BACK`.
Se il dispositivo non dispone dell'obiettivo richiesto, l'SDK usa la prima fotocamera disponibile.
Anche il pulsante per cambiare fotocamera è nascosto sui dispositivi che hanno una sola fotocamera.
Imposta un'opzione del selettore su `false` per bloccare l'utente sull'obiettivo predefinito di quel passaggio.```kotlin theme={null}
val configuration = Configuration(
    defaultLivenessCamera = CameraLens.BACK,
    showLivenessCameraSwitchButton = false
)
```> [!NOTE]
>
> Le opzioni `showLanguageSelector`, `showCloseButton`, `showExitConfirmation` e `closeOnComplete` corrispondono a `DiditSdkConfiguration` del Web SDK. Le opzioni specifiche per dispositivi mobili `languageLocale` e `fontFamily` esistono perché l'SDK mobile visualizza l'intera interfaccia di verifica in modo nativo (a differenza del Web SDK, che delega al frontend ospitato all'interno di un iframe).> [!NOTE]
>
> **Tema e colori**: colori, sfondi e impostazioni della schermata introduttiva si configurano tramite le tue [impostazioni White label](https://business.didit.me) nella Didit Console, non nella configurazione dell'SDK. Così il branding resta coerente su tutte le piattaforme.***## Supporto linguisticoL'SDK supporta **54 lingue**. Se non viene specificata alcuna lingua, l'SDK usa la lingua del dispositivo, con l'inglese come lingua di riserva.```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)
```**[Visualizza tutte le lingue supportate →](https://docs.didit.me/it/integration/supported-languages.md)*****## Opzioni avanzatePer i parametri avanzati della sessione (`contact_details`, `expected_details`, `metadata`, `callback`), usa il metodo **Sessione backend**. Il tuo backend chiama l'[API per la creazione della sessione di verifica](https://docs.didit.me/it/sessions-api/create-session.md) con tutti i parametri, quindi passa il `session_token` all'SDK.***## Gestione dei risultatiLa classe sealed `VerificationResult` fornisce l'esito della verifica:### Casi del risultato| Caso | Descrizione |
| - | - |
| `Completed(session)` | Il flusso di verifica è stato completato (controlla `session.status` per l'esito) |
| `Cancelled(session)` | L'utente ha annullato il flusso di verifica |
| `Failed(error, session)` | Si è verificato un errore durante la verifica |### Proprietà di SessionData| Proprietà | Tipo | Descrizione |
| - | - | - |
| `sessionId` | `String` | Identificatore univoco della sessione |
| `status` | `VerificationStatus` | `APPROVED`, `PENDING` oppure `DECLINED` |### Tipi di erroreTutti gli errori sono sottoclassi sealed di `me.didit.sdk.VerificationError`:| Errore | Descrizione |
| - | - |
| `SessionExpired` | La sessione è scaduta |
| `NetworkError` | Problema di connettività di rete |
| `CameraAccessDenied` | Autorizzazione della fotocamera non concessa |
| `NotInitialized` | SDK non inizializzato: chiama `DiditSdk.initialize(context)` prima |
| `ApiError` | Il backend ha restituito una risposta di errore |
| `RetryBlocked` | La verifica non può essere ripetuta (ad esempio, raggiunto il numero massimo di tentativi) |
| `Unknown(message)` | Altro errore con messaggio |### Connessione persaSe il dispositivo perde la connessione durante la verifica, l'SDK copre il flusso con una schermata "Nessuna connessione a Internet" invece di lasciare un passaggio in caricamento.
Continua a verificare in background e chiude la schermata da sola non appena Didit torna raggiungibile; l'utente prosegue dal passaggio in cui si trovava.
La schermata offre **Riprova** e, quando `showCloseButton` è `true` (il valore predefinito), **Esci dalla verifica**.
Uscendo, la verifica termina con `VerificationResult.Failed(error = VerificationError.NetworkError, session = ...)`, così la tua app sa che l'utente è uscito a causa della connessione.### Esempio completo di gestione del risultato```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
        }
    }
}
```***## Osservare lo stato dell'SDKPuoi osservare lo stato dell'SDK per creare un'interfaccia di caricamento personalizzata:```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 / R8L'SDK include le proprie regole ProGuard consumer. Non è necessaria alcuna configurazione aggiuntiva.Se usi la modalità completa di R8, potresti dover aggiungere questo al tuo `gradle.properties`:```properties theme={null}
android.enableR8.fullMode=false
```***## Esempio end-to-end (sessione lato backend → SDK Android → risultato)Questo schema è l'integrazione pronta per la produzione. Il tuo backend crea la sessione, la tua app Android riceve il `session_token` e l'SDK esegue il flusso.### 1. Backend: creare la sessione```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: scambiare il token e avviare l'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: ricevere la decisione finale tramite webhookIl risultato dell'SDK è utile per il feedback nell'interfaccia, ma l'esito definitivo arriva tramite webhook. Consulta la [guida ai Webhook](https://docs.didit.me/it/integration/webhooks.md) per la verifica 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);
});
```***## Esempio 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.