> ## 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 iOS Swift de verificación de identidad: KYC móvil

> SDK nativo de Didit para iOS en Swift: verificación de identidad, prueba de vida biométrica y lectura NFC de pasaportes. Pago por uso, $10 gratis/mes.



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



      
      

\<pre>

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

\## 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.9.1 (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.9.1")
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.9.1/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>



      
      

Pegar en

Un SDK de iOS ligero y controlado desde el servidor para la verificación de identidad, que requiere una configuración mínima. **Última versión: 4.9.1.**> [card] [Repositorio de GitHub](https://github.com/didit-protocol/sdk-ios)
>
> Consulta el código fuente, las versiones y el registro de cambios completo en GitHub> [!NOTE]
>
> ### **SDK nativo**: Este es el enfoque recomendado para apps de iOS. Los SDK nativos ofrecen la mejor experiencia de usuario, una gestión optimizada de la cámara y compatibilidad completa con NFC.***## Requisitos| Requisito | Versión mínima |
| - | - |
| iOS | 13.0+ |
| Xcode | 15.0+ |
| Swift | 5.9+ |### Compatibilidad con versiones de iOS| Versión de iOS | Funciones disponibles |
| - | - |
| iOS 13.0 - 14.x | Todas las funciones **excepto** la lectura NFC de pasaportes |
| iOS 15.0+ | Todas las funciones, incluida la lectura NFC de pasaportes |> [!NOTE]
>
> **El consentimiento biométrico requiere la versión nativa 4.10.0 o posterior.** Para las personas amparadas por la legislación de Illinois, Texas o Colorado, Didit puede solicitar un [consentimiento biométrico](https://docs.didit.me/es/getting-started/biometric-consent.md) explícito antes de la primera captura facial. El SDK de iOS 4.10.0 y las versiones posteriores muestran ese paso. Las versiones anteriores no pueden mostrarlo: sus sesiones funcionan como hasta ahora y la decisión indica que el consentimiento no se recopiló (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). Actualiza si verificas a personas en esos estados.***## InstalaciónDesde la versión `4.0.0`, el SDK se distribuye en **cuatro variantes instalables**, de modo que tu aplicación solo asume el tamaño binario de las funciones que usa. Elige exactamente una variante: un subspec de CocoaPods y un producto de biblioteca de SwiftPM:| Variante | CocoaPods | Producto de SwiftPM | NFC | Detección automática | OpenSSL | iOS mínimo |
| - | - | - | :-: | :-: | - | - |
| **Core** | `DiditSDK/Core` | `DiditSDKCore` | – | – | ninguno | iOS 13.0+ |
| **AutoDetection** | `DiditSDK/AutoDetection` | `DiditSDKAutoDetection` | – | ✓ | ninguno | iOS 13.0+ |
| **NFC** | `DiditSDK/NFC` | `DiditSDKNFC` | ✓ | – | `3.3.3` incluido | iOS 15.0+ |
| **All** (predeterminada) | `DiditSDK/All` | `DiditSDK` | ✓ | ✓ | `3.3.3` incluido | iOS 15.0+ |- **Core**: la huella más pequeña, solo captura manual. Sin `OpenSSL.xcframework`, sin runtime de CoreNFC y sin runtime de ML.
- **AutoDetection**: captura automática de documentos y rostros basada en ML, pero sin lectura del chip NFC.
- **NFC**: lectura del chip NFC de pasaportes y eID sin el runtime de ML de captura automática.
- **All**: todas las funciones. Es la opción predeterminada cuando instalas `DiditSDK` sin indicar un subspec o producto.Lo que cada variante añade al bundle de tu aplicación (Mach-O arm64, medido con `4.9.0`): **Core** \~11.1 MB, **NFC** \~11.7 MB más \~4 MB de OpenSSL, **AutoDetection** \~16.0 MB, **All** \~16.6 MB más OpenSSL.
Los modelos de detección se descargan en tiempo de ejecución y se almacenan en caché, por lo que nunca cuentan en el tamaño de descarga de tu aplicación.Desde la versión `4.7.1`, las variantes **AutoDetection** y **All** ejecutan la inferencia de captura automática en un runtime de ML más ligero, en lugar del runtime de MediaPipe usado hasta `4.6.0`. Se trata de una transición, no de una variante opcional: se aplica sin condiciones a cualquiera que use `4.7.1` o una versión posterior, así que no existe una variante independiente con el "motor anterior" que puedas instalar en su lugar. Medido sobre los artefactos publicados: **-3.4 MB (-28%)** en el payload de descarga comprimido de la App Store y **-8.5 MB (-35%)** en el binario arm64 incluido en tu aplicación (el framework sin comprimir para dispositivo es unos 12 MB más pequeño). Antes de cada lanzamiento se verifica, fotograma a fotograma y en una matriz de dispositivos físicos, que el comportamiento de detección es idéntico al del motor anterior, y la inferencia de documentos es apreciablemente más rápida.> [!NOTE]
>
> **Revertir el cambio de runtime**: como se trata de una transición y no de una variante, revertirlo implica fijar tu dependencia a `4.6.0` (SwiftPM: selecciona la versión `4.6.0` en lugar de "Up to Next Major"; CocoaPods: apunta `podspec_url` a la etiqueta `4.6.0`), no cambiar un flag. Didit supervisa el rendimiento real de este runtime durante un ciclo de versiones tras su lanzamiento; si aparece una regresión, la respuesta será un aviso para fijar la versión anterior más una versión de parche sobre el runtime actual, nunca un cambio de variante, ya que no existe ninguna.Desde la versión `4.6.0`, los frameworks distribuidos ya no incluyen descriptores de ABI de Swift (metadatos de compilación que Xcode copiaba en cada aplicación pero nunca leía) ni videos tutoriales que la variante no puede reproducir. Actualizar desde `4.5.4` o una versión anterior reduce tu aplicación en unos 7-8 MB por sí solo, sin cambios de código.
La App Store comprime los binarios para su entrega, por lo que el coste de descarga inalámbrica es menor: consulta el informe de tamaño de la aplicación en App Store Connect para ver la diferencia exacta por dispositivo.> [!NOTE]
>
> Las variantes **NFC** y **All** incluyen `OpenSSL.xcframework` (**OpenSSL 3.3.3**, distribuido como `OpenSSL-Universal 3.3.3001` a través de `NFCPassportReader`), que es necesario para la autenticación del chip NFC y requiere iOS 15.0+. Las versiones **hasta la 4.0.6 inclusive** incluían OpenSSL `1.1.1s`; **la 4.0.7 y posteriores** incluyen OpenSSL 3.3.3 con su propio manifiesto de privacidad y firma de código: instala siempre **la 4.0.7 o una posterior**. Ten en cuenta que actualizar alinea las *versiones* de OpenSSL, pero no elimina los conflictos al *incrustar*: si otra dependencia de tu aplicación también incrusta un `OpenSSL.framework` (mismo nombre de archivo, mismo bundle id `com.github.krzyzanowskim.OpenSSL`), las dos copias entran en conflicto en el paso de incrustación sin importar la versión. Conserva exactamente una copia; por ejemplo, anula el otro paquete mediante su identidad de SPM para que use el `OpenSSL.xcframework` publicado por Didit, de modo que el binario del bundle sea aquel con el que se compiló este SDK. Las variantes **Core** y **AutoDetection** no enlazan OpenSSL en absoluto.`import DiditSDK` es igual en el código de tu aplicación, sea cual sea la variante que instales.### Swift Package Manager (recomendado)Añade el paquete a tu proyecto desde Xcode:1) Ve a **File > Add Package Dependencies**
2) Introduce la URL del repositorio:```
https://github.com/didit-protocol/sdk-ios.git
```3) Selecciona la versión (o **Up to Next Major** desde `4.9.1`) y haz clic en **Add Package**
4) Cuando se te pida elegir un producto, selecciona exactamente un producto de biblioteca para tu variante (consulta la tabla anterior)O bien en tu `Package.swift`:```swift theme={null}
dependencies: [
    .package(url: "https://github.com/didit-protocol/sdk-ios.git", from: "4.9.1")
]
```Después, añade exactamente uno de estos productos a tu target:```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 no aplica por ti el mínimo de iOS 15.** `Package.swift` declara
> `platforms: [.iOS(.v13)]` para todo el paquete, por lo que Xcode te permitirá añadir `DiditSDK` o
> `DiditSDKNFC` a un target de iOS 13 o 14 sin advertencias, pero ambos incluyen `OpenSSL.xcframework`
> y leen chips mediante `NFCPassportReader`, que requieren **iOS 15.0+**. Establece tú mismo el deployment
> target de tu target en 15.0 cuando uses el producto `All` o `NFC`. CocoaPods lo aplica
> automáticamente mediante el `deployment_target` del subspec.### CocoaPods`DiditSDK` se distribuye como un podspec binario alojado en el repositorio (no está en el CocoaPods Trunk público), por lo que debes hacer referencia a la URL del podspec. Elige exactamente un subspec:```ruby theme={null}
podspec_url = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.9.1/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` y `AutoDetection` son compatibles con iOS 13; `NFC` y `All` requieren iOS 15 debido a `NFCPassportReader`.Después ejecuta:```bash theme={null}
pod install
```> [!NOTE]
>
> Después de `pod install`, abre el `.xcworkspace` generado (no el `.xcodeproj`).> [!NOTE]
>
> **Errores de rsync en Xcode 15+**: si ves errores de rsync `Operation not permitted` durante la compilación, establece **Build Settings → User Script Sandboxing** (`ENABLE_USER_SCRIPT_SANDBOXING`) en **No** en el proyecto, tanto para Debug como para Release.### Manual (XCFramework)Cada versión publica un XCFramework por variante. Descarga los archivos zip de tu variante desde la página de [GitHub Releases](https://github.com/didit-protocol/sdk-ios/releases), arrastra las carpetas `.xcframework` a Xcode y selecciona **Embed & Sign**.| Variante | Descarga |
| - | - |
| **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` |***## PermisosEl SDK requiere los siguientes permisos. Agrégalos al `Info.plist` de tu aplicación:| Permiso | Clave de Info.plist | Descripción | Obligatorio |
| - | - | - | - |
| Cámara | `NSCameraUsageDescription` | Escaneo de documentos y verificación facial | ✅ Sí |
| Micrófono | `NSMicrophoneUsageDescription` | Grabación de video para las pruebas de vida | ✅ Sí |
| Fototeca | `NSPhotoLibraryUsageDescription` | Subida de documentos desde la galería del dispositivo | ✅ Sí |
| NFC | `NFCReaderUsageDescription` | Lectura de chips NFC en pasaportes y documentos de identidad | ⚠️ Solo SDK completo |
| Ubicación | `NSLocationWhenInUseUsageDescription` | Geolocalización para la prevención del fraude | ❌ Opcional |### Ejemplo de entradas de 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>
```### Configuración de NFCSolo es necesaria si instalas la variante **NFC** o **All**. Omite esta sección si instalaste la variante **Core** o **AutoDetection**.Para habilitar la lectura NFC de pasaportes y documentos de identidad con chip:1) **Agrega la capacidad NFC** en Xcode:
   * Selecciona tu target → **Signing & Capabilities** → **+ Capability** → **Near Field Communication Tag Reading**

2) **Agrega los identificadores ISO7816** a `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` permite que el SDK lea la My Number Card de Japón mediante [JPKI](https://docs.didit.me/es/core-technology/nfc-verification/overview.md#my-number-card-de-japón-jpki): sin él, iOS no notifica la tarjeta al SDK. La lectura de la My Number Card aún no está habilitada en producción, y el identificador no cambia nada para los demás documentos, así que puedes agregarlo ya.3) **Agrega los entitlements** (en tu archivo `.entitlements`):```xml theme={null}
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>TAG</string>
</array>
```> [!WARNING]
>
> **Limitación del simulador (variantes NFC y All)**: estas variantes enlazan CoreNFC y, desde Xcode 12, `libnfshared.dylib` no está disponible en los simuladores. Consulta [este hilo de Stack Overflow](https://stackoverflow.com/questions/63915728/xcode12-corenfc-simulator-library-not-loaded) para ver una solución alternativa. Esto **no** afecta a la variante **Core** ni a la **AutoDetection**. Prueba las funciones NFC solo en dispositivos físicos.> [!NOTE]
>
> ### **Revisión de App Store (variantes NFC y All)**: si instalas la variante **NFC** o **All**, Apple puede solicitar un video de demostración durante la revisión, porque el código relacionado con NFC forma parte del binario del SDK, aunque tu flujo de verificación no use NFC. Solicita nuestro video de demostración de NFC para enviarlo a Apple escribiendo a [support@didit.me](mailto:support@didit.me). Esto no afecta a la variante **Core** ni a la **AutoDetection**.***## Inicio rápido### Integración con 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)")
        }
    }
}
```### Integración con 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")
    }
}
```***## Métodos de integraciónEl SDK admite dos métodos de integración:### Método 1: UniLink (el más sencillo)No requiere backend. El SDK crea la sesión directamente con el ID de tu flujo de la [Didit Console](https://business.didit.me). El método UniLink (`startVerification(workflowId:)`) solo admite `vendorData`; para cualquier otro parámetro de sesión, usa el método 2.> [!NOTE]
>
> Para que `vendorData` se asocie a la sesión mediante UniLink, habilita la opción **Datos del Proveedor** en la [Didit Console](https://business.didit.me).```swift theme={null}
DiditSdk.shared.startVerification(
    workflowId: "your-workflow-id",
    vendorData: "user-123"
)
```### Método 2: sesión desde el backend (recomendado para producción)Tu backend crea la sesión mediante la [API de creación de sesiones de verificación](https://docs.didit.me/es/sessions-api/create-session.md) (`POST /v3/session/`) con todos los parámetros disponibles (`contact_details`, `expected_details`, `metadata`, `callback`, etc.) y luego pasa el `session_token` al 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)
```Este enfoque te da control total sobre:- La asociación de las sesiones con tus usuarios (`vendor_data`)
- La configuración de los datos de contacto y los datos esperados para la validación cruzada
- La configuración de metadatos personalizados
- La configuración de callbacks por sesión
  Estos datos (datos de contacto, datos esperados, metadatos y callback) se envían a la [API de creación de sesiones de verificación](https://docs.didit.me/es/sessions-api/create-session.md).***## ConfiguraciónPersonaliza el comportamiento del SDK con `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
)
```### Opciones de configuración| Propiedad | Tipo | Valor predeterminado | Descripción |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | Configuración regional del dispositivo | Fuerza un idioma concreto |
| `showLanguageSelector` | `Bool` | `false` | Muestra el selector de idioma de estilo web en la pantalla de bienvenida |
| `fontFamily` | `String?` | Fuente del sistema | Nombre de una familia tipográfica personalizada (debe estar registrada en tu aplicación mediante `UIAppFonts` en `Info.plist`) |
| `loggingEnabled` | `Bool` | `false` | Activa los registros de depuración del SDK |
| `showCloseButton` | `Bool` | `true` | Muestra el botón de cerrar (X) en las pantallas de los pasos de verificación |
| `showExitConfirmation` | `Bool` | `true` | Muestra un diálogo de confirmación cuando el usuario intenta salir |
| `closeOnComplete` | `Bool` | `false` | Cierra automáticamente la interfaz de verificación al terminar (equivalente en el Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `.back` | Lente que se usa al abrir la pantalla de captura del documento |
| `defaultLivenessCamera` | `CameraLens` | `.front` | Lente que se usa al abrir la pantalla de captura facial (prueba de vida) |
| `showDocumentCameraSwitchButton` | `Bool` | `true` | Muestra el selector de cámara durante la captura en la pantalla de captura del documento |
| `showLivenessCameraSwitchButton` | `Bool` | `true` | Muestra el selector de cámara durante la captura en la pantalla de captura facial |### Opciones de cámaraLas opciones de cámara coinciden con las [opciones de cámara del Web SDK](https://docs.didit.me/es/integration/web-sdks/javascript-sdk.md#opciones-de-cámara).
Cada lente puede ser `.front` o `.back`.
Si el dispositivo no tiene la lente solicitada, el SDK usa la primera cámara disponible.
El selector de cámara también se oculta en los dispositivos que solo tienen una cámara.
Establece una opción de selector en `false` para restringir al usuario a la lente predeterminada de ese paso.```swift theme={null}
let configuration = DiditSdk.Configuration(
    defaultLivenessCamera: .back,
    showLivenessCameraSwitchButton: false
)
```> [!NOTE]
>
> **Temas y colores**: los colores, los fondos y la configuración de la pantalla de introducción se definen en tu [configuración de marca blanca](https://business.didit.me) en la consola de Didit, no en la configuración del SDK. Así se garantiza una imagen de marca coherente en todas las plataformas.> [!NOTE]
>
> Las opciones `showLanguageSelector`, `showCloseButton`, `showExitConfirmation` y `closeOnComplete` coinciden con la `DiditSdkConfiguration` del Web SDK. Las opciones específicas de móvil `languageLocale` y `fontFamily` existen porque el SDK móvil renderiza de forma nativa toda la interfaz de verificación (a diferencia del Web SDK, que delega en el frontend alojado dentro de un iframe).***## Compatibilidad de idiomasEl SDK admite **54 idiomas**. Si no se especifica ningún idioma, el SDK usa la configuración regional del dispositivo, con el inglés como alternativa.```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()
```**[Ver todos los idiomas admitidos →](https://docs.didit.me/es/integration/supported-languages.md)*****## Parámetros avanzados de sesiónPara los parámetros avanzados de sesión (`contact_details`, `expected_details`, `metadata`, `callback`), usa el método **Backend Session**. Tu backend invoca la [API Create Verification Session](https://docs.didit.me/es/sessions-api/create-session.md) con todos los parámetros y después pasa el `session_token` al SDK.***## Gestión de resultadosEl enum `VerificationResult` proporciona el resultado de la verificación:### Casos de resultado| Caso | Descripción |
| - | - |
| `.completed(session:)` | El flujo de verificación ha finalizado (consulta `session.status` para conocer el resultado) |
| `.cancelled(session:)` | El usuario canceló el flujo de verificación |
| `.failed(error:session:)` | Se produjo un error durante la verificación |### Propiedades de SessionData| Propiedad | Tipo | Descripción |
| - | - | - |
| `sessionId` | `String` | Identificador único de la sesión |
| `status` | `VerificationStatus` | `.approved`, `.pending` o `.declined` |
| `country` | `String?` | Código de país (ISO 3166-1 alfa-3) |
| `documentType` | `String?` | Tipo de documento usado en la verificación |### Tipos de error| Error | Descripción |
| - | - |
| `.sessionExpired` | La sesión ha expirado |
| `.networkError` | Problema de conectividad de red |
| `.cameraAccessDenied` | No se concedió el permiso de cámara |
| `.unknown(String)` | Otro error, con mensaje |### Pérdida de conexiónSi el dispositivo pierde la conexión durante la verificación, el SDK muestra una pantalla de "No internet connection" durante el flujo en lugar de dejar un paso cargando.
Sigue comprobando la conexión en segundo plano y cierra la pantalla por sí solo en cuanto se puede volver a conectar con Didit, y el usuario continúa desde el paso en el que estaba.
La pantalla ofrece **Try Again** y, cuando `showCloseButton` es `true` (el valor predeterminado), **Exit Verification**.
Al salir, la verificación termina con `.failed(error: .networkError, session:)`, de modo que tu aplicación sabe que el usuario salió debido a la conexión.### Ejemplo completo de gestión de resultados```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
    }
}
```***## Cerrar la verificación mediante código> [!NOTE]
>
> Disponible en DiditSDK **3.6.0+**.La app anfitriona puede finalizar una verificación activa mediante código con `DiditSdk.shared.dismiss()`. Es la forma recomendada de cerrar la verificación cuando la app anfitriona necesita recuperar el control de la pantalla, por ejemplo, cuando la app pasa a segundo plano.```swift theme={null}
DiditSdk.shared.dismiss()
````dismiss()` pasa por el flujo de finalización normal del SDK: cierra la interfaz presentada, restablece el estado interno e invoca el handler `.diditVerification` con `.cancelled(session:)`, que incluye el `sessionId` actual si se llegó a crear una sesión. No tiene ningún efecto cuando no hay ninguna verificación activa.### Ejemplo: cerrar cuando la app pasa a segundo plano```swift theme={null}
NotificationCenter.default.addObserver(
    forName: UIApplication.didEnterBackgroundNotification,
    object: nil,
    queue: .main
) { _ in
    DiditSdk.shared.dismiss()
}
```> [!WARNING]
>
> **No** asignes `DiditSdk.shared.isPresented = false` para cerrar la verificación: el indicador solo dispara la presentación en su flanco de subida, y asignarle `false` no tiene ningún efecto. Del mismo modo, no se admite invocar `dismiss(animated:)` de UIKit en el view controller superior: omite el flujo de finalización del SDK, por lo que tu handler `.diditVerification` nunca se ejecuta.***## Observar el estado del SDKPuedes observar el estado del SDK para mostrar una interfaz de carga personalizada:```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)")
            }
        }
    }
}
```***## Ejemplo de extremo a extremo (sesión en el backend → SDK de iOS → resultado)Este patrón es la integración preparada para producción. Tu backend crea la sesión, tu app de iOS recibe el `session_token` y el SDK ejecuta el flujo.### 1. Backend: crear la sesión```ts theme={null}
// Node.js / Express example. Run on your server. NEVER ship DIDIT_API_KEY to the device.
import express from "express";

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

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

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

  const { session_id, session_token } = await response.json();
  // Persist session_id <-> userId so you can match the webhook later.
  res.json({ session_id, session_token });
});
```### 2. iOS: intercambiar el token e iniciar el 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: recibir la decisión final mediante webhookEl resultado del SDK es útil para proporcionar comentarios en la interfaz, pero el resultado definitivo llega mediante webhook. Consulta la [guía de webhooks](https://docs.didit.me/es/integration/webhooks.md) para la verificación HMAC.```ts theme={null}
app.post("/api/webhooks/didit", express.raw({ type: "application/json" }), (req, res) => {
  // 1. Verify the X-Signature header (see Webhooks docs)
  // 2. Parse the body
  const event = JSON.parse(req.body.toString());
  if (event.webhook_type === "status.updated") {
    // event.session_id, event.status ("Approved" | "Declined" | "In Review" | ...)
    // Look up the user by session_id and update their verification state.
  }
  res.sendStatus(200);
});
```***## Ejemplo completo con 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.