> ## 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 KYC iOS Swift untuk Verifikasi Identitas

> SDK iOS Swift dari Didit untuk verifikasi identitas, liveness biometrik, dan NFC e-paspor. Harga per penggunaan, gratis $10/bulan, tanpa kontrak.



Prompt Integrasi iOS SDK
        Salin prompt ke papan klip



      
      

\<pre>

\`Integrate Didit identity verification into my iOS app using the native Swift SDK (DiditSDK 4.13.2).

\## Requirements
\- iOS 13.0+, Xcode 15.0+, Swift 5.9+
\- NFC chip reading requires iOS 15+ and a compatible device with NFC hardware
\- Since 4.0.0 the SDK ships in four variants; pick exactly one:
\- Core (DiditSDKCore): no NFC, no auto-detection, no OpenSSL, iOS 13.0+, smallest binary (manual capture only)
\- AutoDetection (DiditSDKAutoDetection): ML auto-capture, no NFC, no OpenSSL, iOS 13.0+
\- NFC (DiditSDKNFC): NFC passport reading, bundles OpenSSL 3.3.3, iOS 15.0+
\- All (DiditSDK — default): every feature, bundles OpenSSL 3.3.3, iOS 15.0+

\## Installation

\### Option A: Swift Package Manager (recommended)
1\. In Xcode: File > Add Package Dependencies
2\. Enter URL: https://github.com/didit-protocol/sdk-ios.git
3\. Select version 4.13.2 (or "Up to Next Major") and click Add Package
4\. Add exactly one library product for your variant:
\- All (NFC + auto-detection): product "DiditSDK"
\- Core (no NFC, no auto-detection): product "DiditSDKCore"
\- AutoDetection (auto-capture, no NFC): product "DiditSDKAutoDetection"
\- NFC (NFC, no auto-detection): product "DiditSDKNFC"

In Package.swift:
.package(url: "https://github.com/didit-protocol/sdk-ios.git", from: "4.13.2")
Then add one product, e.g. .product(name: "DiditSDK", package: "DiditSDK") or .product(name: "DiditSDKCore", package: "DiditSDK"). Your code always writes import DiditSDK regardless of variant.

\### Option B: CocoaPods (binary podspec — DiditSDK is not on the public Trunk)
podspec_url = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.13.2/DiditSDK.podspec'
\# Pick exactly one subspec:
\# All (NFC + auto-detection, iOS 15+):
platform :ios, '15.0'
pod 'DiditSDK/All', :podspec => podspec_url
\# Core (no NFC, no auto-detection, iOS 13+):        pod 'DiditSDK/Core', :podspec => podspec_url
\# AutoDetection (auto-capture, no NFC, iOS 13+):    pod 'DiditSDK/AutoDetection', :podspec => podspec_url
\# NFC (NFC, no auto-detection, iOS 15+):            pod 'DiditSDK/NFC', :podspec => podspec_url

Then run: pod install
Open the .xcworkspace (not .xcodeproj).

On Xcode 15+ if you hit rsync "Operation not permitted", set Build Setting ENABLE_USER_SCRIPT_SANDBOXING to No on the project (Debug and Release).

\## Required Permissions (Info.plist)
\- NSCameraUsageDescription (required) — Document scanning and face verification
\- NSMicrophoneUsageDescription (required) — Video recording for liveness checks
\- NSPhotoLibraryUsageDescription (required) — Upload documents from gallery
\- NFCReaderUsageDescription (only if using the NFC or All variant) — Read NFC chips in passports/IDs
\- NSLocationWhenInUseUsageDescription (optional) — Geolocation for fraud prevention

\## NFC Configuration (NFC or All variant only — skip for the Core or AutoDetection variants)
1\. Add "Near Field Communication Tag Reading" capability in Xcode > Signing & Capabilities
2\. Add ISO7816 identifiers to Info.plist:
com.apple.developer.nfc.readersession.iso7816.select-identifiers:
\["D23300000045737445494420763335", "A0000002471001", "A0000002472001", "00000000000000", "D392F000260100000001"]
(D392F000260100000001 is the Japan My Number Card's JPKI application: without it, iOS does not report that card to the SDK.)
3\. Add to entitlements file:
com.apple.developer.nfc.readersession.formats: ["TAG"]

\## 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 iOS app (never expose DIDIT_API_KEY to the device).

\## SwiftUI Integration (recommended)
import SwiftUI
import DiditSDK

struct ContentView: View {
var body: some View {
    Button("Verify Identity") {
        // Option A: With session token from your backend (recommended)
        DiditSdk.shared.startVerification(token: "session-token-from-backend")

        // Option B: With workflow ID (SDK creates session internally — UniLink, vendorData only)
        // DiditSdk.shared.startVerification(workflowId: "your-workflow-id", vendorData: "user-id")
    }
    .diditVerification { result in
        switch result {
        case .completed(let session):
            // session.status: VerificationStatus = .approved | .pending | .declined
            if session.status == .approved { /* grant access */ }
        case .cancelled(let session):
            // User dismissed the flow; session may be nil if none was created
            \_ = session
        case .failed(let error, _):
            // VerificationError — show error.localizedDescription
            \_ = error
        }
    }
}
}

\## Programmatically dismissing the verification (3.6.0+)
Call DiditSdk.shared.dismiss() to end an active verification (e.g. on app backgrounding).
It dismisses the UI, resets state, and fires the .diditVerification handler with .cancelled(session:).
Do NOT toggle DiditSdk.shared.isPresented = false or call UIKit dismiss() on the topmost VC — that bypasses the completion pipeline.

\## Result Statuses (SDK enum / API string)
\- .approved / "Approved"  — user identity verified, grant access
\- .declined / "Declined"  — verification failed, show retry or contact support
\- .pending  / "In Review" — 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 iOS app)
\- DIDIT_API_KEY — from Didit Console > API & Webhooks
\- DIDIT_WORKFLOW_ID — from Didit Console > Workflows

\## App Store Note
If you ship the NFC or All variant, Apple may request an NFC demo video during review. Request ours from [support@didit.me](mailto:support@didit.me).

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

\</pre>



      
      

Tempel ke

SDK iOS ringan dan digerakkan oleh server untuk verifikasi identitas dengan konfigurasi minimal. **Versi terbaru: 4.13.2.**> [card] [Repositori GitHub](https://github.com/didit-protocol/sdk-ios)
>
> Lihat kode sumber, rilis, dan log perubahan lengkap di GitHub> [!NOTE]
>
> ### **SDK Native**: Ini adalah pendekatan yang direkomendasikan untuk aplikasi iOS. SDK native memberikan pengalaman pengguna terbaik, penanganan kamera yang dioptimalkan, dan dukungan NFC penuh.***## Persyaratan| Persyaratan | Versi Minimum |
| - | - |
| iOS | 13.0+ |
| Xcode | 15.0+ |
| Swift | 5.9+ |### Kompatibilitas Versi iOS| Versi iOS | Fitur yang Tersedia |
| - | - |
| iOS 13.0 - 14.x | Semua fitur **kecuali** pembacaan paspor NFC |
| iOS 15.0+ | Semua fitur termasuk pembacaan paspor NFC |> [!NOTE]
>
> **Persetujuan biometrik memerlukan SDK native 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 iOS 4.10.0 dan yang lebih baru menampilkan langkah tersebut. Versi sebelumnya tidak dapat menampilkan langkah ini: sesi mereka berjalan seperti biasa, dan laporan keputusan menyatakan bahwa persetujuan tidak dikumpulkan (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). Tingkatkan versi jika Anda memverifikasi orang di negara bagian tersebut.***## InstalasiSejak `4.0.0`, SDK tersedia dalam beberapa varian yang dapat diinstal, sehingga aplikasi Anda hanya menanggung ukuran biner dari fitur yang benar-benar digunakan. Pilih tepat satu varian: satu subspec CocoaPods dan satu produk library SwiftPM.| Varian | CocoaPods | Produk SwiftPM | NFC | Deteksi otomatis | OpenSSL | iOS minimum |
| - | - | - | :-: | :-: | - | - |
| **Core** | `DiditSDK/Core` | `DiditSDKCore` | – | ✓ | tidak ada | iOS 13.0+ |
| **AutoDetection** (tidak digunakan lagi) | `DiditSDK/AutoDetection` | `DiditSDKAutoDetection` | – | ✓ | tidak ada | iOS 13.0+ |
| **NFC** | `DiditSDK/NFC` | `DiditSDKNFC` | ✓ | ✓ | `3.3.3` disertakan | iOS 15.0+ |
| **All** (default) | `DiditSDK/All` | `DiditSDK` | ✓ | ✓ | `3.3.3` disertakan | iOS 15.0+ |- **Core**: footprint terkecil, dengan pengambilan dokumen dan swafoto otomatis menggunakan detektor ringan milik Didit sendiri. Tidak ada `OpenSSL.xcframework` dan tidak ada runtime CoreNFC.
- **AutoDetection**: tidak digunakan lagi sejak 4.11.0 dan identik dengan **Core**. Gunakan **Core** sebagai gantinya.
- **NFC**: **Core** ditambah pembacaan chip paspor/eID NFC.
- **All**: semua fitur. Ini adalah default saat Anda menginstal `DiditSDK` tanpa menyebutkan subspec/produk.Yang ditambahkan setiap varian ke bundle aplikasi Anda (arm64 Mach-O, diukur terhadap `4.9.0`): **Core** \~11.1 MB, **NFC** \~11.7 MB ditambah \~4 MB OpenSSL, **AutoDetection** \~16.0 MB, **All** \~16.6 MB ditambah OpenSSL.
Model deteksi itu sendiri diunduh saat runtime dan di-cache, sehingga tidak pernah dihitung terhadap ukuran unduhan aplikasi Anda.Sejak `4.11.0`, pengambilan otomatis berjalan di detektor ringan milik Didit sendiri di setiap varian. TensorFlow Lite tidak lagi menjadi bagian dari SDK, dan framework menjadi lebih kecil karena terjemahannya dimuat dari luar biner.Sejak `4.6.0`, framework yang dikirimkan tidak lagi memuat Swift ABI descriptors (metadata build yang disalin Xcode ke setiap aplikasi tetapi tidak pernah dibaca) atau video tutorial yang tidak dapat diputar oleh varian tersebut. Saat memperbarui dari `4.5.4` atau sebelumnya, aplikasi Anda menyusut sekitar 7-8 MB dengan sendirinya, tanpa perubahan kode.
App Store mengompres biner untuk pengiriman, sehingga biaya over-the-air lebih rendah. Periksa laporan ukuran aplikasi di App Store Connect untuk selisih per perangkat yang tepat.> [!NOTE]
>
> Varian **NFC** dan **All** menyertakan `OpenSSL.xcframework` (**OpenSSL 3.3.3**, dikirim sebagai `OpenSSL-Universal 3.3.3001` melalui `NFCPassportReader`), yang diperlukan untuk autentikasi chip NFC dan membutuhkan iOS 15.0+. Rilis **hingga dan termasuk 4.0.6** menyertakan OpenSSL `1.1.1s`; **4.0.7 dan yang lebih baru** mengirimkan OpenSSL 3.3.3 dengan privacy manifest dan tanda tangan kodenya sendiri. Selalu instal **4.0.7 atau yang lebih baru**. Perlu dicatat bahwa pembaruan menyelaraskan *versi* OpenSSL, tetapi tidak menghapus *benturan embed*: jika dependensi lain di aplikasi Anda juga meng-embed `OpenSSL.framework` (nama file sama, bundle id `com.github.krzyzanowskim.OpenSSL` yang sama), kedua salinan akan bertabrakan pada tahap embed, terlepas dari versinya. Simpan tepat satu salinan. Misalnya, timpa paket lain berdasarkan identitas SPM agar menggunakan `OpenSSL.xcframework` yang dipublikasikan Didit, sehingga biner di bundle adalah yang dibangun bersama SDK ini. Varian **Core** dan **AutoDetection** tidak menautkan OpenSSL sama sekali.`import DiditSDK` sama di kode aplikasi Anda, apa pun varian yang Anda instal.### Swift Package Manager (Direkomendasikan)Tambahkan package ke proyek Anda menggunakan Xcode:1) Buka **File > Add Package Dependencies**
2) Masukkan URL repositori:```
https://github.com/didit-protocol/sdk-ios.git
```3) Pilih versi (atau **Up to Next Major** dari `4.13.2`) lalu klik **Add Package**
4) Saat diminta memilih produk, pilih tepat satu produk library untuk varian Anda (lihat tabel di atas)Atau di `Package.swift` Anda:```swift theme={null}
dependencies: [
    .package(url: "https://github.com/didit-protocol/sdk-ios.git", from: "4.13.2")
]
```Lalu tambahkan tepat satu produk berikut ke target Anda:```swift theme={null}
// All (default — NFC + auto-detection)
.product(name: "DiditSDK", package: "DiditSDK")

// Core (no NFC, no auto-detection, no OpenSSL)
.product(name: "DiditSDKCore", package: "DiditSDK")

// AutoDetection (auto-capture, no NFC)
.product(name: "DiditSDKAutoDetection", package: "DiditSDK")

// NFC (NFC passport reading, no auto-detection)
.product(name: "DiditSDKNFC", package: "DiditSDK")
```> [!WARNING]
>
> **Swift Package Manager tidak menerapkan batas minimum iOS 15 untuk Anda.** `Package.swift` mendeklarasikan `platforms: [.iOS(.v13)]` untuk seluruh package, sehingga Xcode akan membiarkan Anda menambahkan `DiditSDK` atau `DiditSDKNFC` ke target iOS 13 atau 14 tanpa peringatan. Namun, keduanya menyertakan `OpenSSL.xcframework` dan membaca chip melalui `NFCPassportReader`, yang membutuhkan **iOS 15.0+**. Atur target deployment aplikasi Anda ke 15.0 sendiri saat menggunakan produk `All` atau `NFC`. CocoaPods menerapkannya secara otomatis melalui `deployment_target` subspec.### CocoaPods`DiditSDK` didistribusikan sebagai podspec biner yang di-host di repositori (tidak tersedia di CocoaPods Trunk publik), sehingga Anda harus mereferensikan URL podspec. Pilih tepat satu subspec:```ruby theme={null}
podspec_url = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.13.2/DiditSDK.podspec'

# All (NFC + auto-detection, iOS 15.0+):
platform :ios, '15.0'
pod 'DiditSDK/All', :podspec => podspec_url

# Core (no NFC, no auto-detection, iOS 13.0+):
# pod 'DiditSDK/Core', :podspec => podspec_url

# AutoDetection (auto-capture, no NFC, iOS 13.0+):
# pod 'DiditSDK/AutoDetection', :podspec => podspec_url

# NFC (NFC passport reading, iOS 15.0+):
# pod 'DiditSDK/NFC', :podspec => podspec_url
````Core` dan `AutoDetection` mendukung mulai iOS 13; `NFC` dan `All` membutuhkan iOS 15 karena `NFCPassportReader`.Lalu jalankan:```bash theme={null}
pod install
```> [!NOTE]
>
> Setelah `pod install`, buka `.xcworkspace` yang dihasilkan (bukan `.xcodeproj`).> [!NOTE]
>
> **Error rsync Xcode 15+**: Jika Anda melihat error rsync `Operation not permitted` saat build, atur **Build Settings → User Script Sandboxing** (`ENABLE_USER_SCRIPT_SANDBOXING`) ke **No** pada proyek untuk Debug dan Release.### Manual (XCFramework)Setiap rilis mempublikasikan satu XCFramework per varian. Unduh zip untuk varian Anda dari [GitHub Releases](https://github.com/didit-protocol/sdk-ios/releases), lalu seret folder `.xcframework` ke Xcode dan atur **Embed & Sign**.| Varian | Unduhan |
| - | - |
| **Core** | `DiditSDK-Core.xcframework.zip` |
| **AutoDetection** | `DiditSDK-AutoDetection.xcframework.zip` |
| **NFC** | `DiditSDK-NFC.xcframework.zip` + `OpenSSL.xcframework.zip` |
| **All** | `DiditSDK.xcframework.zip` + `OpenSSL.xcframework.zip` |***## PermissionsSDK memerlukan izin berikut. Tambahkan izin ini ke `Info.plist` aplikasi Anda:| Izin | Kunci Info.plist | Deskripsi | Wajib |
| - | - | - | - |
| Kamera | `NSCameraUsageDescription` | Pemindaian dokumen dan verifikasi wajah | ✅ Ya |
| Mikrofon | `NSMicrophoneUsageDescription` | Perekaman video untuk pemeriksaan liveness | ✅ Ya |
| Pustaka Foto | `NSPhotoLibraryUsageDescription` | Unggah dokumen dari galeri perangkat | ✅ Ya |
| NFC | `NFCReaderUsageDescription` | Membaca chip NFC pada paspor dan kartu identitas | ⚠️ Hanya SDK penuh |
| Lokasi | `NSLocationWhenInUseUsageDescription` | Geolokasi untuk pencegahan penipuan | ❌ Opsional |### Contoh Entri Info.plist```xml theme={null}
<key>NSCameraUsageDescription</key>
<string>Camera access is required to scan your identity documents for verification.</string>

<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required to record video for liveness verification.</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is required to upload document images.</string>

<key>NFCReaderUsageDescription</key>
<string>NFC access is required to read the chip in your identity document.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access helps verify your identity and prevent fraud.</string>
```### Konfigurasi NFCHanya diperlukan saat memasang varian **NFC** atau **All**. Lewati bagian ini jika Anda memasang varian **Core** atau **AutoDetection**.Untuk mengaktifkan pembacaan NFC pada paspor dan kartu identitas yang memiliki chip:1) **Tambahkan Kapabilitas NFC** di Xcode:
   * Pilih target Anda → **Signing & Capabilities** → **+ Capability** → **Near Field Communication Tag Reading**

2) **Tambahkan identifier ISO7816** ke `Info.plist`:```xml theme={null}
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
    <string>D23300000045737445494420763335</string>
    <string>A0000002471001</string>
    <string>A0000002472001</string>
    <string>00000000000000</string>
    <string>D392F000260100000001</string>
</array>
````D392F000260100000001` memungkinkan SDK membaca Japan My Number Card melalui [JPKI](https://docs.didit.me/id/core-technology/nfc-verification/overview.md#japan-my-number-card-jpki). Tanpa identifier ini, iOS tidak melaporkan kartu tersebut ke SDK. Pembacaan My Number Card belum diaktifkan di produksi, dan identifier ini tidak berpengaruh pada dokumen lain, jadi Anda dapat menambahkannya sekarang.3) **Tambahkan Entitlements** (di file `.entitlements` Anda):```xml theme={null}
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>TAG</string>
</array>
```> [!WARNING]
>
> **Keterbatasan Simulator (varian NFC dan All)**: Varian ini menautkan CoreNFC, dan sejak Xcode 12 `libnfshared.dylib` tidak tersedia di simulator. Lihat [utas Stack Overflow ini](https://stackoverflow.com/questions/63915728/xcode12-corenfc-simulator-library-not-loaded) untuk solusinya. Ini **tidak** berlaku untuk varian **Core** atau **AutoDetection**. Uji fitur NFC hanya pada perangkat fisik.> [!NOTE]
>
> ### **Peninjauan App Store (varian NFC dan All)**: Jika Anda memasang varian **NFC** atau **All**, Apple mungkin meminta video demo selama peninjauan karena kode terkait NFC merupakan bagian dari binary SDK, meskipun alur kerja Anda tidak menggunakan NFC. Hubungi [support@didit.me](mailto:support@didit.me) untuk meminta video demo NFC kami yang akan diserahkan kepada Apple. Ini tidak berlaku untuk varian **Core** atau **AutoDetection**.***## Mulai Cepat### Integrasi SwiftUI```swift theme={null}
import SwiftUI
import DiditSDK

struct ContentView: View {
    var body: some View {
        Button("Verify Identity") {
            // Method 1: UniLink — no backend required
            DiditSdk.shared.startVerification(workflowId: "your-workflow-id")
            
            // Method 2: Backend Session — full parameter control
            // DiditSdk.shared.startVerification(token: "your-session-token")
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            print("Completed: \(session.status)")
        case .cancelled(let session):
            print("Cancelled")
        case .failed(let error, _):
            print("Failed: \(error.localizedDescription)")
        }
    }
}
```### Integrasi UIKit```swift theme={null}
import UIKit
import DiditSDK

class VerificationViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Start verification when ready
        DiditSdk.shared.startVerification(token: "your-session-token")
    }
}
```***## 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 [Didit Console](https://business.didit.me). Metode UniLink (`startVerification(workflowId:)`) hanya mendukung `vendorData`. Untuk parameter sesi lainnya, gunakan Metode 2.> [!NOTE]
>
> Agar `vendorData` dilampirkan ke sesi melalui UniLink, aktifkan opsi **Data Vendor** di [Didit Console](https://business.didit.me).```swift theme={null}
DiditSdk.shared.startVerification(
    workflowId: "your-workflow-id",
    vendorData: "user-123"
)
```### 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 penuh (`contact_details`, `expected_details`, `metadata`, `callback`, dll.), lalu meneruskan `session_token` ke SDK.```swift theme={null}
// Your backend creates a session and returns the token
let sessionToken = await yourBackend.createVerificationSession(userId: currentUser.id)

// Pass the token to the SDK
DiditSdk.shared.startVerification(token: sessionToken)
```Pendekatan ini memberi Anda kendali penuh atas:- Mengaitkan sesi dengan pengguna Anda (`vendor_data`)
- Menetapkan detail kontak dan detail yang diharapkan untuk validasi silang
- Menetapkan metadata kustom
- Mengonfigurasi callback per sesi
  Data ini (detail kontak, detail yang diharapkan, metadata, callback) dikirim ke [API Pembuatan Sesi Verifikasi](https://docs.didit.me/id/sessions-api/create-session.md).***## KonfigurasiSesuaikan perilaku SDK dengan `DiditSdk.Configuration`:```swift theme={null}
let configuration = DiditSdk.Configuration(
    languageLocale: .spanish,      // Force Spanish language
    showLanguageSelector: true,    // Let the user change language
    fontFamily: "Avenir",          // Custom font (must be registered in your app)
    loggingEnabled: true,          // Enable debug logging
    showCloseButton: true,         // Show close (X) button on step screens
    showExitConfirmation: true,    // Show confirmation dialog when user taps close
    closeOnComplete: false         // Don't auto-dismiss on completion
)

DiditSdk.shared.startVerification(
    token: "your-session-token",
    configuration: configuration
)
```### Opsi Konfigurasi| Properti | Tipe | Default | Deskripsi |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | Locale perangkat | Paksa penggunaan bahasa tertentu |
| `showLanguageSelector` | `Bool` | `false` | Tampilkan pemilih bahasa bergaya web di layar selamat datang |
| `fontFamily` | `String?` | Font sistem | Nama keluarga font kustom (harus didaftarkan di aplikasi Anda melalui `UIAppFonts` di `Info.plist`) |
| `loggingEnabled` | `Bool` | `false` | Aktifkan log debug SDK |
| `showCloseButton` | `Bool` | `true` | Tampilkan tombol tutup (X) di layar langkah verifikasi |
| `showExitConfirmation` | `Bool` | `true` | Tampilkan dialog konfirmasi saat pengguna mencoba keluar |
| `closeOnComplete` | `Bool` | `false` | Tutup otomatis UI verifikasi saat selesai (setara dengan Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `.back` | Lensa yang digunakan saat layar pengambilan dokumen terbuka |
| `defaultLivenessCamera` | `CameraLens` | `.front` | Lensa yang digunakan saat layar pengambilan wajah (liveness) terbuka |
| `showDocumentCameraSwitchButton` | `Bool` | `true` | Tampilkan pengalih kamera pada layar pengambilan dokumen |
| `showLivenessCameraSwitchButton` | `Bool` | `true` | Tampilkan 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 `.front` atau `.back`.
Jika perangkat tidak memiliki lensa yang diminta, SDK menggunakan kamera pertama yang dimilikinya.
Pengalih kamera juga disembunyikan pada perangkat yang hanya memiliki satu kamera.
Atur opsi pengalih ke `false` untuk mengunci pengguna pada lensa default langkah tersebut.```swift theme={null}
let configuration = DiditSdk.Configuration(
    defaultLivenessCamera: .back,
    showLivenessCameraSwitchButton: false
)
```> [!NOTE]
>
> **Tema & Warna**: Warna, latar belakang, dan pengaturan layar pengantar dikonfigurasi melalui [pengaturan White Label](https://business.didit.me) Anda di Didit Console, bukan di konfigurasi SDK. Ini memastikan branding yang konsisten di semua platform.> [!NOTE]
>
> Opsi `showLanguageSelector`, `showCloseButton`, `showExitConfirmation`, dan `closeOnComplete` sesuai dengan `DiditSdkConfiguration` Web SDK. Opsi khusus mobile `languageLocale` dan `fontFamily` ada karena SDK mobile merender UI verifikasi lengkap secara native (berbeda dengan Web SDK yang menyerahkannya ke frontend yang di-hosting di dalam iframe).***## Dukungan BahasaSDK mendukung **54 bahasa**. Jika tidak ada bahasa yang ditentukan, SDK menggunakan locale perangkat dengan bahasa Inggris sebagai cadangan.```swift theme={null}
// Use device locale (default)
let config = DiditSdk.Configuration()

// Force specific language
let config = DiditSdk.Configuration(languageLocale: .french)

// Let the user change language on the welcome screen
let config = DiditSdk.Configuration(showLanguageSelector: true)

// Detect device locale programmatically
let deviceLanguage = SupportedLanguage.fromDeviceLocale()
```**[Lihat Semua Bahasa yang Didukung →](https://docs.didit.me/id/integration/supported-languages.md)*****## Parameter Sesi LanjutanUntuk parameter sesi lanjutan (`contact_details`, `expected_details`, `metadata`, `callback`), gunakan metode **Backend Session**. Backend Anda memanggil [API Create Verification Session](https://docs.didit.me/id/sessions-api/create-session.md) dengan parameter lengkap, lalu meneruskan `session_token` ke SDK.***## Menangani HasilEnum `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` | Pengidentifikasi sesi yang unik |
| `status` | `VerificationStatus` | `.approved`, `.pending`, atau `.declined` |
| `country` | `String?` | Kode negara (ISO 3166-1 alpha-3) |
| `documentType` | `String?` | Tipe dokumen yang digunakan untuk verifikasi |### Tipe Error| Error | Deskripsi |
| - | - |
| `.sessionExpired` | Sesi telah kedaluwarsa |
| `.networkError` | Masalah konektivitas jaringan |
| `.cameraAccessDenied` | Izin kamera belum diberikan |
| `.unknown(String)` | Error lain dengan pesan |### Koneksi terputusJika perangkat kehilangan koneksi selama verifikasi, SDK menampilkan layar "Tidak ada koneksi internet" di atas alur alih-alih membiarkan langkah terus memuat.
SDK terus memeriksa di latar belakang dan menutup layar dengan sendirinya begitu Didit dapat dihubungi kembali, lalu pengguna melanjutkan dari langkah yang sedang mereka jalankan.
Layar ini menampilkan **Coba Lagi** dan, jika `showCloseButton` bernilai `true` (default), **Keluar dari Verifikasi**.
Keluar akan mengakhiri verifikasi dengan `.failed(error: .networkError, session:)`, sehingga aplikasi Anda tahu bahwa pengguna keluar karena masalah koneksi.### Contoh Lengkap Penanganan Hasil```swift theme={null}
.diditVerification { result in
    switch result {
    case .completed(let session):
        switch session.status {
        case .approved:
            print("✅ Approved! Session: \(session.sessionId)")
            // User is verified - grant access
            
        case .pending:
            print("⏳ Under review. Session: \(session.sessionId)")
            // Show "verification in progress" UI
            
        case .declined:
            print("❌ Declined. Session: \(session.sessionId)")
            // Handle declined verification
        }
        
    case .cancelled(let session):
        if let session = session {
            print("🚫 Cancelled session: \(session.sessionId)")
        }
        // User chose to cancel - maybe show retry option
        
    case .failed(let error, let session):
        print("⚠️ Error: \(error.localizedDescription)")
        // Handle error - show retry or contact support
    }
}
```***## Menutup Verifikasi secara Programatik> [!NOTE]
>
> Tersedia di DiditSDK **3.6.0+**.Aplikasi host dapat mengakhiri verifikasi yang sedang aktif secara programatik dengan `DiditSdk.shared.dismiss()`. Ini adalah cara yang direkomendasikan untuk menutup verifikasi saat host perlu mengambil alih layar, misalnya ketika aplikasi berpindah ke latar belakang.```swift theme={null}
DiditSdk.shared.dismiss()
````dismiss()` melewati alur penyelesaian normal SDK: ia menutup UI yang ditampilkan, mengatur ulang status internal, dan memanggil handler `.diditVerification` dengan `.cancelled(session:)` yang membawa `sessionId` saat ini jika sesi sudah dibuat. Pemanggilan ini tidak melakukan apa pun jika tidak ada verifikasi yang aktif.### Contoh: menutup saat aplikasi masuk ke latar belakang```swift theme={null}
NotificationCenter.default.addObserver(
    forName: UIApplication.didEnterBackgroundNotification,
    object: nil,
    queue: .main
) { _ in
    DiditSdk.shared.dismiss()
}
```> [!WARNING]
>
> **Jangan** mengatur `DiditSdk.shared.isPresented = false` untuk menutup, karena flag ini hanya memicu presentasi saat nilainya berubah dari false ke true, sehingga mengaturnya ke `false` tidak berpengaruh apa pun. Begitu pula, memanggil `dismiss(animated:)` dari UIKit pada pengontrol tampilan paling atas tidak didukung: cara ini melewati alur penyelesaian SDK sehingga handler `.diditVerification` Anda tidak pernah dipanggil.***## Memantau Status SDKAnda dapat memantau status SDK untuk membuat UI pemuatan kustom:```swift theme={null}
struct CustomView: View {
    @ObservedObject private var sdk = DiditSdk.shared
    
    var body: some View {
        VStack {
            switch sdk.state {
            case .idle:
                Text("Ready to verify")
            case .creatingSession:
                ProgressView("Creating session...")
            case .loading:
                ProgressView("Loading...")
            case .ready:
                Text("Verification in progress")
            case .error(let message):
                Text("Error: \(message)")
            }
        }
    }
}
```***## Contoh End-to-End (Sesi Backend → SDK iOS → Hasil)Pola ini adalah integrasi yang siap produksi. Backend Anda membuat sesi, aplikasi iOS 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. iOS: tukar token dan mulai SDK```swift theme={null}
import SwiftUI
import DiditSDK

struct VerifyButton: View {
    let userId: String
    @State private var error: String?

    var body: some View {
        Button("Verify Identity") {
            Task { await start() }
        }
        .diditVerification { result in
            switch result {
            case .completed(let session) where session.status == .approved:
                // Optimistically reflect success in the UI; rely on the webhook
                // delivered to your backend as the source of truth.
                break
            case .completed(let session):
                print("Terminal status: \(session.status.rawValue)")
            case .cancelled:
                print("User cancelled")
            case .failed(let err, _):
                error = err.localizedDescription
            }
        }
    }

    private func start() async {
        do {
            var req = URLRequest(url: URL(string: "https://your-backend.example.com/api/verification/start")!)
            req.httpMethod = "POST"
            req.setValue("application/json", forHTTPHeaderField: "Content-Type")
            req.httpBody = try JSONEncoder().encode(["userId": userId])

            let (data, _) = try await URLSession.shared.data(for: req)
            struct Payload: Decodable { let session_token: String }
            let payload = try JSONDecoder().decode(Payload.self, from: data)

            await MainActor.run {
                DiditSdk.shared.startVerification(token: payload.session_token)
            }
        } catch {
            self.error = error.localizedDescription
        }
    }
}
```### 3. Backend: terima keputusan akhir melalui webhookHasil SDK memudahkan untuk umpan balik UI, tetapi hasil final yang menjadi acuan 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 SwiftUI```swift theme={null}
import SwiftUI
import DiditSDK

struct HomeView: View {
    @State private var resultMessage: String?
    @State private var isVerified = false
    
    var body: some View {
        VStack(spacing: 24) {
            if isVerified {
                Image(systemName: "checkmark.circle.fill")
                    .font(.system(size: 64))
                    .foregroundColor(.green)
                Text("Identity Verified")
                    .font(.title2)
            } else {
                Button("Verify Identity") {
                    startVerification()
                }
                .font(.headline)
                .padding(.horizontal, 32)
                .padding(.vertical, 16)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(12)
            }
            
            if let message = resultMessage {
                Text(message)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                    .padding()
            }
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func startVerification() {
        let config = DiditSdk.Configuration(
            languageLocale: .english
        )
        
        // Method 1: UniLink — no backend required
        DiditSdk.shared.startVerification(
            workflowId: "your-workflow-id",
            vendorData: "user-123",
            configuration: config
        )
        
        // Method 2: Backend Session — full parameter control
        // DiditSdk.shared.startVerification(
        //     token: "your-session-token",
        //     configuration: config
        // )
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            if session.status == .approved {
                isVerified = true
            }
            resultMessage = """
                Status: \(session.status.rawValue)
                Session: \(session.sessionId)
                Country: \(session.country ?? "N/A")
                Document: \(session.documentType ?? "N/A")
                """
                
        case .cancelled(let session):
            resultMessage = "Cancelled - Session: \(session?.sessionId ?? "unknown")"
            
        case .failed(let error, _):
            resultMessage = "Failed: \(error.localizedDescription)"
        }
    }
}
```***


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