> ## 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 Verifikasi Identitas Android Kotlin: KYC

> Didit menyediakan SDK Kotlin Android untuk verifikasi identitas, liveness, dan NFC e-paspor. Mulai $0.33 per cek KYC penuh, gratis $10/bulan.



Prompt Integrasi SDK Android
        Salin prompt ke papan klip



      
      

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



      
      

Tempel ke

SDK Android yang ringan dan digerakkan oleh server untuk verifikasi identitas dengan konfigurasi minimal.> [card] [Repositori GitHub](https://github.com/didit-protocol/sdk-android)
>
> Lihat kode sumber dan contoh di GitHub> [!NOTE]
>
> ### **SDK Native**: Ini adalah pendekatan yang direkomendasikan untuk aplikasi Android. SDK native memberikan pengalaman pengguna terbaik, penanganan kamera yang dioptimalkan, dan dukungan NFC penuh.***## Persyaratan| Persyaratan | Versi Minimum |
| - | - |
| API Android | 23+ (Android 6.0 Marshmallow). Deteksi otomatis ML memerlukan API 24+ (lihat di bawah). |
| Kotlin | 1.9+ |
| Jetpack Compose | Disertakan sebagai dependensi transitif |> [!NOTE]
>
> **Ketersediaan fitur menurut level API**: Deteksi otomatis dokumen dan wajah memerlukan API 24+ (detektor ringan milik Didit sendiri, yang disertakan dalam `didit-sdk-core`). Pada perangkat API 23, SDK beralih ke pengambilan manual dengan tombol rana berwaktu. Semua fitur lain berfungsi di seluruh rentang API 23+.> [!NOTE]
>
> **Persetujuan biometrik memerlukan SDK native versi 4.10.0 atau yang lebih baru.** Untuk orang yang tercakup oleh hukum Illinois, Texas, atau Colorado, Didit dapat meminta [persetujuan biometrik](https://docs.didit.me/id/getting-started/biometric-consent.md) secara eksplisit sebelum pengambilan wajah pertama. SDK Android 4.10.0 dan yang lebih baru menampilkan langkah tersebut. Versi sebelumnya tidak dapat menampilkan langkah ini: sesi mereka tetap berjalan seperti biasa, dan keputusan melaporkan bahwa persetujuan tidak dikumpulkan (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). Lakukan pembaruan jika Anda memverifikasi orang di negara bagian tersebut.***## Installation### Langkah 1: Tambahkan RepositoriTambahkan repositori Maven Didit ke blok `repositories` di `settings.gradle.kts` Anda:```kotlin theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}
```Atau jika Anda menggunakan `settings.gradle` (Groovy):```groovy theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}
```### Langkah 2: Tambahkan DependensiTambahkan dependensi SDK ke `build.gradle.kts` aplikasi Anda:
(!) Untuk versinya, pastikan Anda memeriksa [repositori GitHub](https://github.com/didit-protocol/sdk-android) untuk versi terbaru.```kotlin theme={null}
dependencies {
    implementation("me.didit:didit-sdk:4.13.2")
}
```Atau jika Anda menggunakan `build.gradle` (Groovy):```groovy theme={null}
dependencies {
    implementation "me.didit:didit-sdk:4.13.2"
}
```#### Varian SDKSDK Android dirilis sebagai artefak terpisah, sehingga aplikasi Anda hanya menanggung ukuran biner dari
fitur yang digunakannya. `me.didit:didit-sdk` di atas adalah bundel lengkap. Pilih yang sesuai dengan aplikasi Anda:| Artefak | Deteksi otomatis (ML) | Pembacaan chip NFC | Gunakan saat |
| - | :-: | :-: | - |
| `me.didit:didit-sdk-core` | ✓ | – | build paling kecil; pengambilan gambar otomatis menggunakan detektor Didit sendiri, tanpa pembacaan chip paspor/dokumen identitas |
| `me.didit:didit-sdk-autodetection` | ✓ | – | sudah tidak direkomendasikan dan kosong sejak 4.11.0; hanya bergantung pada `didit-sdk-core`, jadi gunakan `didit-sdk-core` sebagai gantinya |
| `me.didit:didit-sdk-nfc` | ✓ | ✓ | pembacaan chip di atas `didit-sdk-core` |
| `me.didit:didit-sdk` | ✓ | ✓ | semua fitur (bundel lengkap) |Sejak `4.6.0`, penandatanganan dompet secara native melalui WalletConnect dirilis sebagai add-on opsional tersendiri, `me.didit:didit-sdk-wallet`.
Bundel lengkap `me.didit:didit-sdk` sudah menyertakannya, jadi tidak ada yang berubah jika Anda memasang bundel tersebut.
Jika Anda menggunakan salah satu artefak yang lebih ringan dan ingin konfirmasi kepemilikan dompet berjalan secara native di dalam aplikasi Anda, tambahkan `me.didit:didit-sdk-wallet` di sampingnya; tanpa add-on tersebut, SDK menyelesaikan kepemilikan dompet melalui alur browser yang aman, sehingga fitur tetap berfungsi dalam kedua kondisi. Memindahkan WalletConnect keluar dari `didit-sdk-core` juga menghapus beberapa megabyte dependensi dompet dari setiap build yang tidak membutuhkannya.Semua artefak dipublikasikan dengan versi yang sama, jadi pastikan semuanya tetap menggunakan `4.13.2`.#### Menjaga ukuran unduhan tetap kecilModel deteksi yang digunakan untuk pengambilan gambar otomatis diunduh saat runtime dan disimpan dalam cache, sehingga tidak pernah dihitung dalam ukuran aplikasi Anda.
Yang ditambahkan pengambilan gambar otomatis ke aplikasi Anda adalah pustaka native runtime ML, dan biayanya bergantung pada arsitektur CPU: sekitar 10 MB untuk `arm64-v8a`, 7 MB untuk `armeabi-v7a`, dan 13 MB untuk masing-masing dari dua arsitektur emulator x86.Agar biaya ini hanya dikeluarkan sekali:1) **Publikasikan Android App Bundle (AAB).** Google Play hanya mengirimkan arsitektur dan bahasa milik perangkat, sehingga ponsel arm64 memasang sekitar 10 MB kode native (sekitar 4 MB unduhan terkompresi). APK universal justru menyertakan keempat arsitektur, lebih dari 40 MB, dan ini adalah penyebab paling umum dari hasil pengukuran ukuran yang lebih besar dari perkiraan.

2) **Jika Anda mendistribusikan satu APK** dan target Anda adalah ponsel dan tablet ARM, batasi arsitektur yang disertakan:

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

   Pertahankan setiap ABI yang benar-benar digunakan pengguna Anda. Tambahkan `x86_64` jika Anda menargetkan Chromebook atau perangkat x86 lainnya, atau publikasikan pemisahan APK per ABI agar tidak ada perangkat yang kehilangan dukungan.

3) **Aktifkan R8.** Atur `isMinifyEnabled = true` dan `isShrinkResources = true` di build type rilis Anda (`minifyEnabled true` / `shrinkResources true` jika Anda menggunakan `build.gradle` Groovy). SDK menyertakan aturan konsumen sendiri, sehingga kode SDK yang tidak digunakan dihapus tanpa konfigurasi tambahan.

4) **Batasi bahasa yang disertakan** dengan `resConfigs(...)` jika Anda tidak memerlukan semua 48 locale SDK dalam build APK; pemisahan bahasa AAB menanganinya secara otomatis di Google Play.### Langkah 3: Tambahkan Pengecualian PengemasanTambahkan ini ke blok `android` aplikasi Anda untuk menghindari konflik build:```kotlin theme={null}
android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}
```Selesai! Gradle akan otomatis menyelesaikan semua dependensi transitif.***## IzinSDK memerlukan izin berikut. Izin ini dideklarasikan di `AndroidManifest.xml` milik SDK dan akan digabungkan secara otomatis ke manifest aplikasi Anda:| Izin | Sumber AAR | Deskripsi | Wajib |
| - | - | - | - |
| `INTERNET` | `didit-sdk-core` | Akses jaringan untuk komunikasi API | Ya |
| `ACCESS_NETWORK_STATE` | `didit-sdk-core` | Mendeteksi ketersediaan jaringan | Ya |
| `CAMERA` | `didit-sdk-core` | Pemindaian dokumen dan verifikasi wajah | Ya |
| `NFC` | `didit-sdk-nfc` | Membaca chip NFC pada paspor/kartu identitas | Digabung otomatis dari `didit-sdk-nfc` (dependensi transitif dari `me.didit:didit-sdk`) |### Fitur Kamera dan NFCSDK mendeklarasikan `android.hardware.camera` dan `android.hardware.nfc` sebagai fitur opsional (`android:required="false"`). Hal ini memastikan aplikasi Anda dapat dipasang di perangkat tanpa kamera atau perangkat keras NFC. SDK akan menangani perangkat keras yang tidak tersedia dengan baik saat runtime.***## Mulai Cepat### Langkah 1: Inisialisasi SDKInisialisasi SDK di `Application.onCreate()`:```kotlin theme={null}
import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}
```### Langkah 2: Mulai Verifikasi dan Tangani Hasil```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}")
            }
        }
    }
}
```***## Metode IntegrasiSDK mendukung dua metode integrasi:### Metode 1: UniLink (Paling Sederhana)Tidak memerlukan backend. SDK membuat sesi secara langsung menggunakan ID alur kerja Anda dari Konsol Didit. Hanya terbatas pada `vendorData`.```kotlin theme={null}
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"
) { result ->
    handleResult(result)
}
```### Metode 2: Sesi Backend (Direkomendasikan untuk Produksi)Backend Anda membuat sesi melalui [API Pembuatan Sesi Verifikasi](https://docs.didit.me/id/sessions-api/create-session.md) (`POST /v3/session/`) dengan dukungan parameter lengkap (`contact_details`, `expected_details`, `metadata`, `callback`, dll.), lalu meneruskan `session_token` ke 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)
}
```Pendekatan ini memberi Anda kendali penuh atas:- Mengaitkan sesi dengan pengguna Anda (`vendor_data`)
- Mengatur metadata kustom
- Mengonfigurasi callback per sesi
- Menyediakan detail kontak dan detail yang diharapkan untuk validasi silang***## KonfigurasiSesuaikan perilaku 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)
}
```### Opsi Konfigurasi| Properti | Tipe | Default | Deskripsi |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | Locale perangkat | Menetapkan bahasa tertentu |
| `showLanguageSelector` | `Boolean` | `false` | Menampilkan pemilih bahasa bergaya web di layar selamat datang |
| `fontFamily` | `String?` | Font sistem | Nama resource font kustom (dari `res/font/`) |
| `loggingEnabled` | `Boolean` | `false` | Mengaktifkan logging debug SDK |
| `showCloseButton` | `Boolean` | `true` | Menampilkan tombol tutup (X) di layar langkah verifikasi |
| `showExitConfirmation` | `Boolean` | `true` | Menampilkan dialog konfirmasi saat pengguna mencoba keluar |
| `closeOnComplete` | `Boolean` | `false` | Menutup otomatis UI verifikasi saat selesai (setara dengan Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `CameraLens.BACK` | Lensa yang digunakan saat layar pengambilan dokumen dibuka |
| `defaultLivenessCamera` | `CameraLens` | `CameraLens.FRONT` | Lensa yang digunakan saat layar pengambilan wajah (liveness) dibuka |
| `showDocumentCameraSwitchButton` | `Boolean` | `true` | Menampilkan pengalih kamera pada layar pengambilan dokumen |
| `showLivenessCameraSwitchButton` | `Boolean` | `true` | Menampilkan pengalih kamera pada layar pengambilan wajah |### Opsi kameraOpsi kamera sesuai dengan [opsi kamera Web SDK](https://docs.didit.me/id/integration/web-sdks/javascript-sdk.md#opsi-kamera).
Setiap lensa adalah `CameraLens.FRONT` atau `CameraLens.BACK`.
Jika perangkat tidak memiliki lensa yang diminta, SDK menggunakan kamera pertama yang tersedia.
Pengalih kamera juga disembunyikan pada perangkat yang hanya memiliki satu kamera.
Atur opsi pengalih ke `false` untuk membatasi pengguna pada lensa default langkah tersebut.```kotlin theme={null}
val configuration = Configuration(
    defaultLivenessCamera = CameraLens.BACK,
    showLivenessCameraSwitchButton = false
)
```> [!NOTE]
>
> Opsi `showLanguageSelector`, `showCloseButton`, `showExitConfirmation`, dan `closeOnComplete` sesuai dengan `DiditSdkConfiguration` milik Web SDK. Opsi khusus mobile `languageLocale` dan `fontFamily` ada karena SDK mobile merender UI verifikasi lengkap secara native (tidak seperti Web SDK, yang meneruskan ke frontend yang di-hosting di dalam iframe).> [!NOTE]
>
> **Tema & Warna**: Warna, latar belakang, dan pengaturan layar pengantar dikonfigurasi melalui [pengaturan White Label](https://business.didit.me) Anda di Konsol Didit, bukan di konfigurasi SDK. Hal ini memastikan branding yang konsisten di semua platform.***## Dukungan BahasaSDK mendukung **54 bahasa**. Jika tidak ada bahasa yang ditentukan, SDK menggunakan locale perangkat dengan bahasa Inggris sebagai cadangan.```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)
```**[Lihat Semua Bahasa yang Didukung →](https://docs.didit.me/id/integration/supported-languages.md)*****## Opsi LanjutanUntuk parameter sesi lanjutan (`contact_details`, `expected_details`, `metadata`, `callback`), gunakan metode **Sesi Backend**. Backend Anda memanggil [API Pembuatan Sesi Verifikasi](https://docs.didit.me/id/sessions-api/create-session.md) dengan parameter lengkap, lalu meneruskan `session_token` ke SDK.***## Menangani HasilKelas sealed `VerificationResult` memberikan hasil dari verifikasi:### Kasus Hasil| Kasus | Deskripsi |
| - | - |
| `Completed(session)` | Alur verifikasi selesai (periksa `session.status` untuk hasilnya) |
| `Cancelled(session)` | Pengguna membatalkan alur verifikasi |
| `Failed(error, session)` | Terjadi error selama verifikasi |### Properti SessionData| Properti | Tipe | Deskripsi |
| - | - | - |
| `sessionId` | `String` | Pengenal sesi yang unik |
| `status` | `VerificationStatus` | `APPROVED`, `PENDING`, atau `DECLINED` |### Tipe ErrorSemua error merupakan subclass sealed dari `me.didit.sdk.VerificationError`:| Error | Deskripsi |
| - | - |
| `SessionExpired` | Sesi sudah kedaluwarsa |
| `NetworkError` | Masalah konektivitas jaringan |
| `CameraAccessDenied` | Izin kamera tidak diberikan |
| `NotInitialized` | SDK belum diinisialisasi: panggil `DiditSdk.initialize(context)` terlebih dahulu |
| `ApiError` | Backend mengembalikan respons error |
| `RetryBlocked` | Verifikasi tidak dapat dicoba lagi (misalnya, jumlah percobaan maksimum tercapai) |
| `Unknown(message)` | Error lain dengan pesan |### Koneksi terputusJika perangkat kehilangan koneksi selama verifikasi, SDK menampilkan layar "Tidak ada koneksi internet" selama alur berlangsung, alih-alih membiarkan langkah terus memuat.
SDK terus memeriksa di latar belakang dan menutup layar dengan sendirinya begitu Didit dapat dijangkau kembali, lalu pengguna melanjutkan dari langkah yang sedang mereka jalankan.
Layar ini menampilkan **Try Again** dan, jika `showCloseButton` bernilai `true` (secara default), **Exit Verification**.
Keluar akan mengakhiri verifikasi dengan `VerificationResult.Failed(error = VerificationError.NetworkError, session = ...)`, sehingga aplikasi Anda tahu bahwa pengguna keluar karena masalah koneksi.### Contoh Penanganan Hasil Lengkap```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
        }
    }
}
```***## Memantau Status SDKAnda dapat memantau status SDK untuk UI pemuatan kustom:```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 / R8SDK menyertakan aturan ProGuard consumer-nya sendiri. Tidak diperlukan konfigurasi tambahan.Jika Anda menggunakan mode penuh R8, Anda mungkin perlu menambahkan ini ke `gradle.properties` Anda:```properties theme={null}
android.enableR8.fullMode=false
```***## Contoh End-to-End (Sesi Backend → Android SDK → Hasil)Pola ini adalah integrasi yang siap produksi. Backend Anda membuat sesi, aplikasi Android Anda menerima `session_token`, dan SDK menjalankan alurnya.### 1. Backend: buat sesi```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: tukarkan token dan jalankan 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: terima keputusan akhir melalui webhookHasil SDK berguna untuk umpan balik UI, tetapi hasil resmi diterima melalui webhook. Lihat [panduan webhook](https://docs.didit.me/id/integration/webhooks.md) untuk verifikasi 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);
});
```***## Contoh Lengkap```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.