> For the complete documentation index, see [llms.txt](https://docs.caf.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.caf.io/caf-sdk/ios/getting-started-with-the-sdk-5.md).

# Legacy Getting Started with the SDK

{% hint style="warning" %}
Version 7.0.0 brings an optional, faster way to initialize the SDK with fewer lines of code. Along with this code update, we launched a brand-new, easier-to-read documentation page. To adopt this new setup, [check out the updated guide.](/caf-sdk/ios/getting-started-with-the-sdk.md)
{% endhint %}

## About CafSDK

This technical documentation covers the **implementation of CafSDK for iOS**, detailing the configuration, initialization, execution of capture flows, and advanced customizations.

Currently, CafSDK integrates two main modules: **Face Liveness (FL)** and **Document Detector (DD)**, executed sequentially with a unified configuration interface.

### What is Face Liveness

It is the module that validates the authenticity of a face captured by a photo application, ensuring that the image corresponds to a real person.

**Technical characteristics:**

* URL configuration for authentication (`authBaseUrl`) and liveness verification (`livenessBaseUrl`).
* Flags to enable screen capture and debug mode.
* Support for multiple authentication providers.

### What is Document Detector

It is the module that enables the capture and processing of documents (e.g., ID card, social security card, passport, etc.).

**Technical characteristics:**

* Configuration of a step-by-step flow defined by `CafDocumentDetectorStep` for document capture.
* Operational parameters, such as timeout, manual capture flags, and other settings.
* Possibility of using the camera for framing validations, or document file upload.

***

## Get started with the SDK

**Add the dependency**

CafSDK supports integration via both **Swift Package Manager (SPM) and CocoaPods**, providing flexibility to choose the dependency manager that best suits your project. This guide explains the necessary steps to add CafSDK to your iOS project and provides details about the available modules.

### Requirements to add

To use the CafSDK modules in iOS, ensure that your project meets the minimum requirements:

| Requirement               | Version |
| ------------------------- | ------- |
| **iOS Deployment Target** | 15.0+   |
| **Xcode**                 | 26.0+   |
| **Swift**                 | 6.3+    |

> **Note**: configure your project's Info.plist with the necessary permissions for camera and network access.

* **CAF Mobile Token**: valid [CAF mobileToken](https://github.com/combateafraude/public-docs/blob/docs-sdks/sdk_integration_documentation.md)

### **Steps to add**

**Via Swift Package Manager (SPM)**

**Step 1 - Add the dependency**

Open your project's `Package.swift` file and add the following dependency. This tells Swift Package Manager where to locate the CafSDK repository:

```swift
dependencies: [
    .package(url: "https://github.com/combateafraude/caf-ios-sdk.git", from: "6.4.2")
]
```

**Step 2 - Include the desired products**

After adding the dependency, include the necessary products in your application target. This allows you to integrate the full SDK or select only specific modules, according to your needs:

```swift
.target(
    name: "YourApp",
    dependencies: [
        .product(name: "CafSDK", package: "caf-ios-sdk"),            // Full SDK
        .product(name: "DocumentDetector", package: "caf-ios-sdk"),    // Only DocumentDetector
        .product(name: "CafFaceLiveness", package: "caf-ios-sdk"),       // Only CafFaceLiveness
        .product(name: "IproovProvider", package: "caf-ios-sdk"),        // Optional iProov provider
        .product(name: "FaceTec2DProvider", package: "caf-ios-sdk"),     // Optional FaceTec 2D provider
        .product(name: "FortfaceProvider", package: "caf-ios-sdk")       // Optional Fortface provider (PayFace)
    ]
)
```

**Additional information**

* **Modularity:** integrate only the necessary modules to keep your project lightweight.
* **Compatibility:** the SDK is compatible with iOS 15.0+ and was developed with Swift 5.10+.
* **Version management:** Always check the official repository for the latest version.

### Via CocoaPods

**Step 1 - Update your Podfile**

To integrate CafSDK using CocoaPods, open your project's Podfile and add the following lines. This will instruct CocoaPods to download the necessary artifacts from the official repository:

```bash
# Full SDK
pod 'CafSDKiOS'

# Only DocumentDetector
pod 'CafSDKiOS/DocumentDetector'

# Only CafFaceLiveness
pod 'CafSDKiOS/CafFaceLiveness'

# Optional iProov provider
pod 'CafSDKiOS/IproovProvider'

# Optional FaceTec 2D provider
pod 'CafSDKiOS/FaceTec2DProvider'

# Optional Fortface provider (PayFace)
pod 'CafSDKiOS/FortfaceProvider'

```

**Step 2 - Install the dependencies**

After updating your Podfile, open a terminal in your project's root directory and run:

```bash
pod install
```

This command downloads and integrates all the specific modules into your project.

**Additional Information**

* **Selective integration:** choose only the modules necessary for your project, optimizing performance.
* **Automatic dependency management:** CocoaPods automatically manages version resolution and dependency conflicts.
* **Documentation and support:** for more detailed instructions or troubleshooting, consult the CafSDK documentation.

***

## How to initialize the SDK

This guide explains how to initialize the CafSDK on iOS. It covers the requirements, permissions, global configuration, module-specific configuration, and builder initialization.

### Permissions

For the SDK modules to function correctly, you must declare the following permissions in your **Info.plist**:

**For Face Liveness:**

* **Camera Usage Description (**`NSCameraUsageDescription`**):** explains why the application needs camera access for face detection.
* **Network access:** no explicit permission is required, but ensure your application supports secure connections (HTTPS/WSS).

**For Document Detector:**

* **Camera Usage Description (**`NSCameraUsageDescription`**):** required to capture document images.
* **Photo Library Usage Description (**`NSPhotoLibraryUsageDescription`**):** required if your application supports sending images from the library (optional).

### Security Configuration

Starting from version 6.0.0, CafSDK includes runtime application self-protection (RASP) features. Starting from version 6.4.2, enforcement of these checks is controlled exclusively through the `securityEnabled` property on `CafSDKConfiguration`.

* **Property:** `securityEnabled`
* **Type:** `Bool`
* **Default:** `false`

When set to `true`, the SDK will perform strict security validation during initialization and execution. If a security violation is detected, the SDK will throw a `securityException` and terminate the flow.

**Code example:**

```swift
let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.faceLiveness, .documentDetector],
    securityEnabled: true
)
```

> **Note:** We strongly recommend enabling this flag in production builds to ensure the integrity of the capture process.

> **Migration from `CAFEnforceSecurity`:** The `CAFEnforceSecurity` `Info.plist` flag has been removed in 6.4.2 and is no longer read by the SDK. Set `securityEnabled` on `CafSDKConfiguration` instead.

***

### **Configurations**

The initialization process is divided into two parts: global configuration and module-specific configuration.

**Global configuration**

Create a `CafSDKConfiguration` object, which serves as the central container for all configurations. This configuration defines the execution order of the modules and the visual identity (through a color configuration).

**Code example:**

```swift
let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.faceLiveness, .documentDetector] // Required
)
```

**Module-Specific configuration**

After the global configurations, configure each module individually to adjust the operational, security and visual parameters.

**Document Detector configuration**

Configure the Document Detector module by specifying the capture flow and options such as manual capture and pop-up confirmations.

**Code example:**

```swift
sdkConfig.setDocumentDetectorConfig(CafDocumentDetectorConfig(
    flow: [CafDocumentDetectorStep(stepType: .cnhFull)] // Required for document detector flow
))
```

Consult: [DocumentDetector](#custom-settings-document-detector)

**Face Liveness configuration**

Configure the Face Liveness module to validate that the captured face belongs to a living person. Define options for loading indicators, endpoints and security certificates.

**Code example:**

```swift
sdkConfig.setFaceLivenessConfig(CafFaceLivenessConfig())
```

Consult: [FaceLiveness](#custom-settings-face-liveness)

***

## Builder initialization

Builder initialization is the step where the CafSDK capture flow is configured for execution. Use `CafSdkProvider.Builder` to provide the necessary parameters, including a mobile token, person ID, environment, and the unified callback to handle events.

**Code example:**

```swift
// Create the SDK configuration with the desired modules and custom settings
var sdkConfig = CafSDKConfiguration(
        presentationOrder: [.faceLiveness, .documentDetector]
    ).setDocumentDetectorConfig(CafDocumentDetectorConfig(flow: [CafDocumentDetectorStep(stepType: .cnhFront)])) // Example required document
        .setFaceLivenessConfig(CafFaceLivenessConfig())

// Build the SDK with required parameters and a callback for events
let builder = CafSDKProvider.Builder(
    self,
    mobileToken: "yourToken",
    personId: "personId",
    environment: .prod,
    configuration: sdkConfig,
    callback: { [weak self] event in
        self?.handleUnifiedEvent(event)
    }
)
let sdk = builder.build()

// Start the SDK session
sdk.start()

// Example unified event handler
private func handleUnifiedEvent(_ event: CafUnifiedEvent) {
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        switch event {
        case .loading:
            print("🔄 Loading...")
        case .loaded:
            print("🔄 Loaded")
        case .success(let responses):
            responses.forEach { response in
                print("Module: \(response.moduleName) SignedResponse: \(response.signedResponse)")
            }
        case .failure(let jwtResponse, let type, let description):
            print("Failure: \(type) - \(description ?? "No description")")
            if let jwt = jwtResponse {
                print("JWT response: \(jwt)")
            }
        case .error(let type, let desc):
            print("Error: \(type) \(desc)")
        case .cancelled:
            print("⚠️ Cancelled")
        case .log(let level, let message):
            print("[\(level)] \(message)")
        }
    }
}
```

**Process details**

* **Global configuration:** defines the overall flow and appearance using `presentationOrder` and `CafColorConfiguration`.
* **Module-specific configuration:** customizes the Document Detector and Face Liveness modules with individual settings (e.g., capture flow, loading indicator, API endpoints).
* **Initialization with the Builder:** the builder pattern gathers all the necessary parameters (mobile token, person ID, environment, configuration, and callback) to create and start the SDK.

Following these steps, your iOS project will be correctly configured to use CafSDK, ensuring a robust and efficient integration of the document detection and face verification modules.

### Session Pre-loading (Optional)

The `loadSession()` method allows you to pre-load the user session before starting the SDK flow. This improves the Face Liveness SDK opening time by preparing the session and related resources in advance, resulting in faster startup when `start()` is called.

**When to use:**

* When you want to optimize the user experience by reducing the initial loading time
* When you have the opportunity to pre-load the session before the user actually needs to start the flow
* Particularly useful for Face Liveness module initialization

**Code example:**

```swift
let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.faceLiveness, .documentDetector]
).setFaceLivenessConfig(CafFaceLivenessConfig())

let builder = CafSDKProvider.Builder(
    self,
    mobileToken: "mobile-token",
    personId: "person-id",
    environment: .prod,
    configuration: sdkConfig
) { [weak self] event in
    self?.handleUnifiedEvent(event)
}

let sdk = builder.build()

// Pre-load the session (optional)
sdk.loadSession()

// Later, when ready to start the flow
sdk.start()
```

**Important notes:**

* This method is optional and should be called after `build()` but before `start()`
* Pre-loading the session helps reduce the initial loading time when `start()` is eventually called
* The unified callback will receive `.loading` and `.loaded` events during pre-loading, which can be used to update the UI
* This is particularly beneficial for Face Liveness module initialization

***

## Completing a session

A complete session in CafSDK covers the entire flow, from initialization to completion - whether this completion is a successful validation, an error, or a cancellation by the user.

**Session event handling**

The builder's callback returns a set of events defined by the `CafUnifiedEvent` enumeration. These events include:

* `Loading`: Indicates a sdk loading request
* `Loaded`: Indicates a sdk loading finished request
* `Success(responses: [CafUnifiedResponse])`: Final results (when `waitForAllServices=true`)
* `Failure(response: String?, type: CafFailureType, description: String?)`: Module-specific failures
* `Error(type: CafErrorType, description: String)`: Critical execution errors
* `Cancelled`: User-initiated cancellation
* `Log(level: CafLogLevel, message: String)`: Debugging information

### Error Types Breakdown

### Failure Types (CafFailureType)

| Enum Case         | Raw Value             | Trigger Condition                                   | GPA |  LA |
| ----------------- | --------------------- | --------------------------------------------------- | :-: | :-: |
| `unknown`         | "unknown"             | Generic failure                                     |  ✅  |  ❌  |
| `tooMuchMovement` | "too\_much\_movement" | Excessive head motion                               |  ✅  |  ❌  |
| `tooBright`       | "too\_bright"         | Over-illumination                                   |  ✅  |  ❌  |
| `tooDark`         | "too\_dark"           | Low light conditions                                |  ✅  |  ❌  |
| `misalignedFace`  | "misaligned\_face"    | Face alignment failure                              |  ✅  |  ❌  |
| `eyesClosed`      | "eyes\_closed"        | Closed eyes during capture                          |  ✅  |  ✅  |
| `faceTooFar`      | "face\_too\_far"      | Face too distant                                    |  ✅  |  ❌  |
| `faceTooClose`    | "face\_too\_close"    | Face too close                                      |  ✅  |  ❌  |
| `sunglasses`      | "sunglasses"          | Eye-obscuring eyewear                               |  ✅  |  ❌  |
| `obscuredFace`    | "obscured\_face"      | Partial face obstruction                            |  ✅  |  ✅  |
| `multipleFaces`   | "multiple\_faces"     | Multiple faces detected                             |  ✅  |  ✅  |
| `eyewear`         | "eyewear"             | General eyewear detected that needs removal         |  ⚠️ |  ✅  |
| `faceNotFound`    | "face\_not\_found"    | No face detected in the oval frame                  |  ⚠️ |  ✅  |
| `framesBlurry`    | "frames\_blurry"      | Images are too blurry for processing                |  ⚠️ |  ✅  |
| `lightingIssues`  | "lighting\_issues"    | General lighting issues or glare                    |  ⚠️ |  ✅  |
| `motionIssue`     | "motion\_issue"       | Motion-related capture issues                       |  ⚠️ |  ✅  |
| `backgroundIssue` | "background\_issue"   | Problematic background (too busy or poor contrast)  |  ⚠️ |  ✅  |
| `deviceIssue`     | "device\_issue"       | Hardware or camera-related failure                  |  ⚠️ |  ✅  |
| `deviceRestart`   | "device\_restart"     | Recommendation for device restart                   |  ⚠️ |  ✅  |
| `systemError`     | "system\_error"       | Internal system error                               |  ⚠️ |  ✅  |
| `rejected`        | "rejected"            | Transaction or verification rejected                |  ⚠️ |  ✅  |
| `timeout`         | "timeout"             | The session timed out                               |  ⚠️ |  ✅  |
| `userNotFound`    | "user\_not\_found"    | User could not be identified or found in the system |  ⚠️ |  ✅  |
| `processingFault` | "processing\_fault"   | Internal server-side processing error               |  ⚠️ |  ✅  |

```swift
case .failure(let jwtResponse, let type, let desc):
    switch type {
    case .eyesClosed:
        showAlert("Keep eyes open")
    case .multipleFaces:
        showAlert("Only one face allowed")
    // Handle other cases
    }
```

***

### Error Types (CafErrorType)

| Enum Case                       | Trigger Condition                   |
| ------------------------------- | ----------------------------------- |
| `unsupportedDevice`             | Unsupported device specs            |
| `cameraPermission`              | Camera access denied                |
| `networkException`              | Network connectivity issues         |
| `serverException`               | Backend processing failure          |
| `tokenException`                | Invalid/expired token               |
| `captureAlreadyActiveException` | Concurrent iProov session           |
| `faceAuthentication`            | Face authentication error           |
| `unexpectedErrorException`      | Critical unrecoverable error        |
| `userTimeoutException`          | Capture timeout exceeded            |
| `imageNotFoundException`        | Missing image data                  |
| `tooManyRequestsException`      | API rate limit exceeded             |
| `unknownException`              | Unclassified error                  |
| `libraryException`              | Low-level framework error           |
| `permissionException`           | Missing system permissions          |
| `invalidResponseException`      | Invalid response received           |
| `securityException`             | Runtime security violation detected |

```swift
case .error(let type, let desc):
    switch type {
    case .cameraPermission:
        requestCameraAccess()
    case .networkException:
        showRetryButton()
    case .invalidResponseException:
        showAlert("Received invalid response from server")
    // Handle other errors
    }
```

### Important

A session is considered complete when all modules in the capture flow have finished their operation successfully or when the process is interrupted by an error or a cancellation by the user. In a complete session:

**Full execution**

Each module that finishes successfully sends a `Success` event, including:

* `moduleName`: identifies the module (e.g., "documentDetector" or "faceLiveness") that completed the operation.
* `signedResponse`: A JWT Token containing the result data obtained by the module\`s execution, This data may include information relevant to the process, such as captured images or validation results.

**Interrupted flow**

If an error occurs or the user cancels the process:

* `Error`: a `CafUnifiedEvent.Error` event is triggered with a descriptive error message, allowing you to recover or notify the user.
* `Cancelled`: a `CafUnifiedEvent.Cancelled` event is activated, which allows you to clear resources or present a cancellation message.

**Event Handling Example**

Check out an example of how to handle these events in the unified callback for iOS:

```swift
func handleUnifiedEvent(_ event: CafUnifiedEvent) {
    switch event {
    case .loading:
        // Show a loading indicator
        break
    case .loaded:
        // Update UI to show that modules are ready
        break
    case .success(let responses):
        // Process all successful responses
        responses.forEach { response in
            print("Module: \(response.moduleName) Result: \(response.signedResponse)")
        }
    case .failure(let response, let type, let description):
        // Handle SDK-specific failures with detailed diagnostics
        print("Failure: \(type) - \(description)")
        if let response = response {
            print("JWT response: \(response)")
        }
    case .error(let type, let desc):
        print("Error: \(type) \(desc)")
    case .cancelled:
        // Handle cancellation gracefully
        break
    case .log(let level, let message):
        // Log internal messages for debugging purposes
        print("[\(level)] \(message)")
    }
}
```

**Summary**

* **Complete session:** a session is considered complete when all configured modules finish their tasks successfully, or when an error/cancellation occurs.
* **Centralized management:** The unified callback ensures that, regardless of the outcome, your application will be notified and can take the appropriate action.

This approach ensures robust integration with CafSDK, efficiently handling each state of the capture flow, from start to finish.

***

### Advanced flow

This section explains how to customize and adjust the CafSDK capture flow to meet specific business requirements and enhance the user experience on iOS.

**Module execution order**

The order in which modules are executed is defined by the `presentationOrder` field of the `CafSDKConfiguration` object. This sequence is crucial, as it directly impacts the flow logic. For example, if the process requires the document to be captured before facial validation, the order must reflect this priority.

**Code example:**

```swift
let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.documentDetector, .faceLiveness],
    colorConfig: CafColorConfiguration(
        primaryColor: "#FF0000",
        secondaryColor: "#FFFFFF",
        contentColor: "#FF0000",
        backgroundColor: "#FFFFFF",
        mediumColor: "#00FF00",
        dialogBackgroundColor: "#FFFFFF",
        dialogBorderColor: "#E5E5E7"
    ), // Optional
    waitForAllServices: true, // Optional
    enableTransitionScreens: true // Optional
)
```

### Dark Mode / Light Mode

Dark Mode support is enabled by default in the SDK to ensure a consistent user experience across system themes. However, if you want to apply a custom color scheme, they must first check whether the device is currently using Dark Mode or Light Mode, and configure the `CafColorConfiguration` accordingly.

Use the system's interface style to determine the current mode, then adjust the color configuration to match the desired appearance.

```swift
let userInterfaceStyle = UITraitCollection.current.userInterfaceStyle

let colorConfig: CafColorConfiguration

if userInterfaceStyle == .dark {
    colorConfig = CafColorConfiguration(
        primaryColor: "#FFFFFF",
        secondaryColor: "#222222",
        contentColor: "#FFFFFF",
        backgroundColor: "#000000",
        mediumColor: "#555555",
        dialogBackgroundColor: "#1C1C1E",
        dialogBorderColor: "#E5E5E7"
    )
} else {
    colorConfig = CafColorConfiguration(
        primaryColor: "#FF0000",
        secondaryColor: "#FFFFFF",
        contentColor: "#FF0000",
        backgroundColor: "#FFFFFF",
        mediumColor: "#00FF00",
        dialogBackgroundColor: "#FFFFFF",
        dialogBorderColor: "#E5E5E7"
    )
}

let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.documentDetector, .faceLiveness],
    colorConfig: colorConfig
)
```

### Module-Specific configuration

Customize individual modules using the `setDocumentDetectorConfig` and `setFaceLivenessConfig` methods. These methods allow you to adjust essential parameters, such as:

* **Capture timeout**: defines the maximum time for manual capture.
* **Request timeout**: sets the maximum wait time for a service response.
* **Debugging flags**: enable or disable debugging modes to identify issues during development.
* **Layout and other settings**: adjust visual and operational parameters specific to each module.

**Visual customization**

With the `CafColorConfiguration` object, you can align the visual identity of the capture flow with your application's design. This ensures that visual elements (buttons, backgrounds, and indicators) are consistent with your brand identity.

#### Log Registration and Monitoring

The unified callback implements different log levels (**DEBUG, USAGE, INFO**), allowing detailed monitoring of each step in the flow. These logs are essential for integration with monitoring tools, performance tuning, and real-time issue detection.

**Example in the callback:**

```swift
callback = { event in
    switch event {
    case .log(let level, let message):
        // Log messages for detailed monitoring of the flow
        print("[LOG] \(level): \(message)")
    default:
        break
    }
}
```

**Example of configuration chaining:**

```swift
var sdkConfig = CafSDKConfiguration(
    presentationOrder: [.faceLiveness, .documentDetector],
    colorConfig: CafColorConfiguration(
        primaryColor: "#FF0000",
        secondaryColor: "#FFFFFF",
        contentColor: "#FF0000",
        backgroundColor: "#FFFFFF",
        mediumColor: "#00FF00",
        dialogBackgroundColor: "#FFFFFF",
        dialogBorderColor: "#E5E5E7"
    ),
    waitForAllServices: true, // Optional
    enableTransitionScreens: true // Optional
)
.setDocumentDetectorConfig(CafDocumentDetectorConfig(
    flow: [CafDocumentDetectorStep(stepType: .cnhFull)]
))
.setFaceLivenessConfig(CafFaceLivenessConfig())
```

Consult: [DocumentDetector](#custom-settings-document-detector) and [FaceLiveness](#custom-settings-face-liveness)

\* By chaining these configuration calls, you can precisely control the behavior and appearance of each module in the unified flow.

***

## Custom settings - Face Liveness

The Face Liveness module in CafSDK offers robust measures to ensure that the user's face is real and belongs to a living person. It supports multiple providers, such as iProov, FaceTec2D, and Fortface (PayFace), allowing you to choose or combine solutions based on your requirements.

For detailed customization options, see: Face Liveness Configurations.

**To configure Face Liveness**

The main configuration object is `CafFaceLivenessConfig`, which includes:

* **Instruction configuration:** customizable instructions and steps (via `CafInstructionsConfiguration`) that guide the user.
* **Loading indicator:** a flag (`loadingEnabled`) to display a loading indicator during processing.
* **Endpoint URLs (optional):** `authBaseUrl` (HTTPS) and `livenessBaseUrl` (WSS) for API communication when using a reverse proxy.
* **Certificates (optional):** a list of SHA-256 SPKI encoded base64 hashes for secure communication over WSS, required only when using a reverse proxy.
* **customLocalization (optional):**: This method allows you to specify a custom localization resource name for the iProov module. When a name is provided, the SDK will load the matching localization file instead of the default resource bundle. For further details on the localization files format and integration, please refer to the [iProov Localization documentation](https://github.com/iProov/ios/wiki/Localization).
* **executeFaceAuth:** sets whether to execute face authentication.
* **maxRetryAttempts:** sets the maximum number of retry attempts for face liveness validation. Use `-1` (default) for unlimited retries, `0` for no retries, or any positive `N` to allow up to `N` retries.
* **flCustomizations (optional):** generic customizations for the Face Liveness flow. Includes support for PayFace (Fortface) UI texts and font via `CafFLPayFaceCustomization`.
* **payFaceDebugMode:** enables debug mode for the PayFace provider when `true`.

**Configuration example:**

```swift
sdkConfig.setFaceLivenessConfig(CafFaceLivenessConfig(
    instructionsConfig: CafInstructionsConfiguration(
        enabled: true,
        captureTitle: "Scan Your Face",
        captureDescriptionText: "Follow these steps:",
        captureSteps: ["Hold the phone steady", "Ensure good lighting"],
        captureButtonTitle: "Start Scan",
        captureHeaderImage: UIImage(named: "scan_icon")
    ),
    loadingEnabled: true,
    reverseProxyConfig: CafReverseProxyConfig(
        authBaseUrl: "https://my.proxy.io/v1/faces/",
        livenessBaseUrl: "wss://my.proxy.io/ws/",
        certificates: ["4d69f16113bed7d62ca56feb68d32a0fcb7293d3960="]
    ), // Optional, only used with reverse proxy
    customLocalization: "your-customs-strings-file-name",
    executeFaceAuth: false,
    maxRetryAttempts: -1, // Optional, default is -1 (unlimited). Use 0 for no retries
    payFaceDebugMode: true, // Optional, enables debug mode for PayFace provider
    // Optional PayFace (Fortface) customization
    flCustomizations: [
        CafFLPayFaceCustomization(
            cameraMessageFont: "HelveticaNeue-Bold",
            startMessage: "Center your face and hold still",
            facePositionedMessage: "Perfect! Keep your face centered"
        )
    ]
))
```

### How it works

When `faceLivenessConfig` is set in your `CafSDKConfiguration`, the Face Liveness module will automatically execute when its position in the presentation order is reached. After successful execution, a `CafUnifiedEvent.Success` event is triggered, containing:

* `moduleName`: the module identifier (e.g., "faceLiveness").
* `signedResponse`: A JWT Token containing the result data obtained by the module\`s execution, This data may include information relevant to the process, such as captured images or validation results.

These results can then be processed in your unified callback to update the UI or proceed with your application's flow.

***

## Custom settings

**SDK configuration summary**

The SDK is configured via `CafSDKConfiguration`, which includes settings for:

* UI customization (colors, instructions, and images).
* Reverse proxy endpoints and security certificates (optional).
* Optional parameters like `personId`.

**Reverse Proxy Configuration**

### For Face Liveness (optional)

Use this configuration only if you're routing Face Liveness requests through a reverse proxy.

**Requirements:**

* **Protocol:** `wss://` (WebSocket Secure).
* **Certificates:** Base64-encoded SHA-256 hashes of the certificate's Subject Public Key Info (SPKI).

**Configuration:**

All reverse proxy settings for Face Liveness are defined using the `CafFaceLivenessConfig` structure.

1. **Set the base URL**
   * Use the `livenessBaseUrl` property to define the WSS endpoint.
   * Example: `"wss://my.proxy.io/ws/"`
2. **Set the certificates**
   * Use the `certificates` property to provide the SPKI hashes.
   * Example: `["4d69f16113bed7d62ca56feb68d32a0fcb7293d3960="]`

**Code example:**

```swift
.setFaceLivenessConfig(CafFaceLivenessConfig(
    reverseProxyConfig: CafReverseProxyConfig(
        livenessBaseUrl: "wss://my.proxy.io/ws/",
        certificates: ["4d69f16113bed7d62ca56feb68d32a0fcb7293d3960=",
                   "50f71c5dda30741ee4be1ac378e12539b0d1d511f99=",
                   "9f85e26c1ae41f7ac97adc4099be7f2a40759510ab9="]
    ), // Optional, only used with reverse proxy
))
```

### Authentication reverse proxy (optional)

Use this configuration only if you're routing authentication requests through a reverse proxy.

**Requirement:**

* **Protocol:** `https://`

**Configuration:**

All reverse proxy settings for authentication are defined using the `CafFaceLivenessConfig` structure.

1. **Set the Base URL**
   * Use the `authBaseUrl` property to define the HTTPS endpoint.
   * Example: `"https://my.proxy.io/v1/faces/"`

**Code example:**

```swift
.setFaceLivenessConfig(CafFaceLivenessConfig(
    reverseProxyConfig: CafReverseProxyConfig(
            authBaseUrl: "https://my.proxy.io/v1/faces/",
        ), // Optional, only used with reverse proxy
))
```

***

## **Configuration Structures**

### Caf Face Liveness

Customize the Face Liveness instruction screen.

| Property             | Type                           | Description                                                                                                                        | Default   |
| -------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `loadingEnabled`     | `Bool`                         | Enables/disables the loading screen.                                                                                               | `true`    |
| `authBaseUrl`        | `String`                       | HTTPS URL for authentication requests. Optional. Required only for reverse proxy.                                                  | `""`      |
| `livenessBaseUrl`    | `String`                       | WSS URL for FaceLiveness WebSocket. Optional. Required only for reverse proxy.                                                     | `""`      |
| `certificates`       | `[String]`                     | Base64-encoded SHA-256 SPKI hashes. Optional. Required only for WSS via proxy.                                                     | `[]`      |
| `instructionsConfig` | `CafInstructionsConfiguration` | Customize instructions screen (title, steps, images).                                                                              | See below |
| `executeFaceAuth`    | Boolean                        | Sets whether to execute face authentication.                                                                                       |           |
| `maxRetryAttempts`   | Int                            | Sets the maximum number of retry attempts for face liveness validation. Use `-1` (default) for unlimited retries and `0` for none. | -1        |
| `flCustomizations`   | `[CafFLCustomization]`         | Generic Face Liveness customizations (e.g., PayFace UI texts and font).                                                            | `[]`      |
| `payFaceDebugMode`   | `Bool`                         | Enables debug mode specifically for the PayFace (Fortface) provider.                                                               | `false`   |

### Configuration instructions

Customize the Face Liveness instruction screen.

| Property                 | Type        | Description                                         | Default |
| ------------------------ | ----------- | --------------------------------------------------- | ------- |
| `enabled`                | `Bool`      | Show/hide the instructions screen.                  | `true`  |
| `captureTitle`           | `String?`   | Header title for capture screen.                    | `nil`   |
| `captureDescriptionText` | `String?`   | Brief description for capture screen.               | `nil`   |
| `captureSteps`           | `[String]?` | Ordered list of instructions for capture.           | `nil`   |
| `captureButtonTitle`     | `String?`   | Text for the confirmation button on capture screen. | `nil`   |
| `captureHeaderImage`     | `UIImage?`  | Image displayed at the top of the capture screen.   | `nil`   |
| `uploadTitle`            | `String?`   | Header title for upload screen.                     | `nil`   |
| `uploadDescriptionText`  | `String?`   | Brief description for upload screen.                | `nil`   |
| `uploadSteps`            | `[String]?` | Ordered list of instructions for upload.            | `nil`   |
| `uploadButtonTitle`      | `String?`   | Text for the confirmation button on upload screen.  | `nil`   |
| `uploadHeaderImage`      | `UIImage?`  | Image displayed at the top of the upload screen.    | `nil`   |

### Caf Color Configuration

Personalize the interface. All UI elements from both Face Liveness and Document Detector modules will use these colors.

| Property                | Type     | Description                             | Format                     |
| ----------------------- | -------- | --------------------------------------- | -------------------------- |
| `primaryColor`          | `String` | Primary buttons, highlights.            | Hex code (e.g., `#FF0000`) |
| `secondaryColor`        | `String` | Secondary elements, borders.            | Hex code                   |
| `contentColor`          | `String` | Text and icons.                         | Hex code                   |
| `backgroundColor`       | `String` | Screen background.                      | Hex code                   |
| `mediumColor`           | `String` | Neutral elements (e.g., progress bars). | Hex code                   |
| `dialogBackgroundColor` | `String` | Dialog and popup background color.      | Hex code                   |
| `dialogBorderColor`     | `String` | Dialog and popup border color.          | Hex code                   |

### Code example

#### Complete Configuration Code Example.

```swift
var facelivenessConfig = CafFaceLivenessConfig(
        instructionsConfig: CafInstructionsConfiguration(
            enabled: true,
            captureTitle: "Scan Your Face",
            captureDescriptionText: "Follow these steps:",
            captureSteps: ["Hold the phone steady", "Ensure good lighting"],
            captureButtonTitle: "Start Scan",
            captureHeaderImage: UIImage(named: "scan_icon")
        ), loadingEnabled: true,
        reverseProxyConfig: CafReverseProxyConfig(
            authBaseUrl: "https://my.proxy.io/v1/faces/",
            livenessBaseUrl: "wss://my.proxy.io/ws/",
            certificates: ["4d69f16113bed7d62ca56feb68d32a0fcb7293d3960="]
        ), // Optional, only used with reverse proxy
        executeFaceAuth: false,
        maxRetryAttempts: -1, // Optional, default is -1 (unlimited retries)
    )
```

***

## More Information

#### Certificate Requirements

* Certificates must be the base64-encoded SHA-256 hash of the certificate's Subject Public Key Info (SPKI).

#### **Protocol Application**

* The Face Liveness URL must use **wss\://** when using a reverse proxy.
* The Authentication URL must use **https\://** when using a reverse proxy.

#### **Default Values**

* `loadingEnabled` is `true` by default.
* `instructionsConfig.enabled` is `true` by default.

## SDK Results

### Success cases

After successful execution, the `CafUnifiedEvent.success` event will contain a `[CafUnifiedResponse]` array. For Face Liveness:

```swift
case .success(let responses):
    if let faceResponse = responses.first(where: { $0.moduleName == "faceLiveness" }) {
        let signedResponse = faceResponse.signedResponse
        // Process JWT
    }
```

#### SignedResponse params

Within the `signedResponse`, the parameter `isAlive` defines the execution of liveness, where `true` is approved and `false` is rejected.

| Event        | Description                                                                            |
| ------------ | -------------------------------------------------------------------------------------- |
| `requestId`  | Request identifier.                                                                    |
| `isAlive`    | Validation of a living person, identifies whether the user passed successfully or not. |
| `token`      | Request token.                                                                         |
| `userId`     | User identifier provided for the request.                                              |
| `imageUrl`   | Temporary link to the image, generated by our API.                                     |
| `personId`   | User identifier provided for the SDK.                                                  |
| `sdkVersion` | Sdk version in use.                                                                    |
| `iat`        | Token expiration.                                                                      |

{% hint style="warning" %}
The **isAlive** parameter is **VERY IMPORTANT**, as it dictates whether the validation process proceeds or halts. When `isAlive: true`, the user gains passage to continue their journey; conversely, if `isAlive: false`, the user is deemed invalid and access to further stages of the journey should be denied. This parameter plays a pivotal role in guiding the flow of operations.
{% endhint %}

### Error cases

Refer to [Error Types Breakdown](#error-types-breakdown)

#### Failure Types

The Face Liveness module provides detailed failure reasons through the `CafUnifiedEvent.failure` case. These failure types help identify specific issues during face validation.

```swift
public enum CafFailureType: String, Encodable, CaseIterable {
    case unknown = "unknown"
    case tooMuchMovement = "too_much_movement"
    case tooBright = "too_bright"
    case tooDark = "too_dark"
    case misalignedFace = "misaligned_face"
    case eyesClosed = "eyes_closed"
    case faceTooFar = "face_too_far"
    case faceTooClose = "face_too_close"
    case sunglasses = "sunglasses"
    case eyewear = "eyewear"
    case obscuredFace = "obscured_face"
    case multipleFaces = "multiple_faces"
    case faceNotFound = "face_not_found"
    case framesBlurry = "frames_blurry"
    case lightingIssues = "lighting_issues"
    case motionIssue = "motion_issue"
    case backgroundIssue = "background_issue"
    case deviceIssue = "device_issue"
    case deviceRestart = "device_restart"
    case systemError = "system_error"
    case rejected = "rejected"
    case timeout = "timeout"
    case userNotFound = "user_not_found"
    case processingFault = "processing_fault"
}
```

All failure reasons are exclusively returned in GPA liveness validation flows. In LA (Liveness Assurance) flows, any failure will consistently return the generic `unknown` error.

| FailureType       | Description                                                                                | GPA | LA |
| ----------------- | ------------------------------------------------------------------------------------------ | --- | -- |
| `unknown`         | Try again                                                                                  | ✅   | ❌  |
| `tooMuchMovement` | Keep still                                                                                 | ✅   | ❌  |
| `tooBright`       | Move somewhere darker                                                                      | ✅   | ❌  |
| `tooDark`         | Move somewhere brighter                                                                    | ✅   | ❌  |
| `misalignedFace`  | Keep your face in the oval                                                                 | ✅   | ❌  |
| `faceTooFar`      | Move your face closer to the screen                                                        | ✅   | ❌  |
| `faceTooClose`    | Move your face farther from the screen                                                     | ✅   | ❌  |
| `sunglasses`      | Remove sunglasses                                                                          | ✅   | ❌  |
| `systemError`     | System Error                                                                               | ⚠️  | ✅  |
| `rejected`        | Transaction could not be completed                                                         | ⚠️  | ✅  |
| `faceNotFound`    | Align your face in the oval and then try to keep still                                     | ⚠️  | ✅  |
| `obscuredFace`    | Make sure your whole face is visible and remove any accessories that might cover your face | ✅   | ✅  |
| `timeout`         | System timeout                                                                             | ⚠️  | ✅  |
| `eyewear`         | Remove your eyewear                                                                        | ⚠️  | ✅  |
| `multipleFaces`   | Ensure only one person is visible                                                          | ✅   | ✅  |
| `eyesClosed`      | Make sure your eyes are open                                                               | ✅   | ✅  |
| `userNotFound`    | Transaction could not be completed                                                         | ⚠️  | ✅  |
| `lightingIssues`  | Make sure your face is well lit and free from glare                                        | ⚠️  | ✅  |
| `framesBlurry`    | Align your face in the oval and then try to keep still                                     | ⚠️  | ✅  |
| `deviceIssue`     | Try a different device                                                                     | ⚠️  | ✅  |
| `motionIssue`     | Align your face in the oval and then try to keep still                                     | ⚠️  | ✅  |
| `backgroundIssue` | Move to a different location with a neutral background                                     | ⚠️  | ✅  |
| `deviceRestart`   | Please restart your device and try again                                                   | ⚠️  | ✅  |
| `processingFault` | Please try again                                                                           | ⚠️  | ✅  |

Key: ✅ = will be returned, ❌ = will not be returned, ⚠️ = may be returned in the future

***

## **Custom Settings - Document Detector**

The **DocumentDetector** module uses machine learning (via TensorFlow Lite) to securely detect and validate documents. This module is highly configurable, allowing you to define custom document flows, preview screens, and manual capture settings.

### Document Detector configuration

The main configuration object for this module is the **CafDocumentDetectorConfig**, which offers options such as:

* **Flow:** An array of `CafDocumentDetectorStep` objects to determine the order and type of document captures.
* **Layout Customization:** Define the appearance of the capture interface using the `DocumentDetectorLayout` class. Colors are primarily inherited from the global `CafColorConfiguration`.
* **Upload Settings:** Control file format, compression, and maximum file size with `CafUploadSettings`.
* **Manual Capture Options:** Enable manual capture, adjust the timeout.
* **UI String and Asset Customization:** Use `ddCustomizations` to provide custom texts and images for specific screens like the upload popup and preview screen.
* **Proxy and Timeout Settings:** Configure a proxy and adjust the network timeout for secure document uploads (optional).

#### Code example:

```swift
let documentConfig = CafDocumentDetectorConfig(
    flow: [/* Array of CafDocumentDetectorStep items */], // Required
    layout: CafDocumentDetectorLayout(),
    uploadSettings: CafUploadSettings(enable: true),
    manualCaptureEnabled: true,
    manualCaptureTime: 45,
    requestTimeout: 60,
    showPopup: true,
    ddCustomizations: [
        CafPreviewCustomization(
            title: "Is the photo clear?",
            message: "Ensure all information is readable.",
            okButton: "Yes, it's good!",
            tryAgainButton: "Take again"
        )
    ]
)
```

## Available Documents and Customization

**CafSDK** provides a set of pre-configured documents (e.g., `rgFront`, `cnhFront`, `passport`, etc.). You can customize these documents or create your own flows by adjusting the properties of each `CafDocumentDetectorStep` and `CafDocument`.

### How It Works

When `documentConfig` is set in your `CafSDKConfiguration`, the **Document Detector** module automatically runs when it reaches its designated position in the flow.

After a successful execution, a `CafUnifiedEvent.Success` event is triggered, containing:

* **moduleName:** The module identifier (e.g., `"documentDetector"`).
* **signedResponse:** A JWT Token containing the result data obtained by the module\`s execution, This data may include information relevant to the process, such as captured images or validation results.

These results are then processed in your unified call response, allowing you to proceed with the flow or store the captured information as needed.

#### Code example:

```swift
sdkConfig.setDocumentDetectorConfig(CafDocumentDetectorConfig(
    flow: [CafDocumentDetectorStep(stepType: .rgFront)],
    manualCaptureEnabled: true,
    manualCaptureTime: 45,
    requestTimeout: 60,
    showPopup: true
))
```

After the document capture and processing are completed, the **Document Detector** module triggers a `CafUnifiedEvent.Success` event, which includes:

* **moduleName:** The module identifier (e.g., `"documentDetector"`).
* **result:** The captured document data.

***

## Custom configurations - Document Detector

To configure the Caf Document Detector, use the `CafDocumentDetectorConfig` structure, which includes:

* Document capture flow steps.
* User interface (UI) layout customization.
* UI String and Asset customizations for specific screens.
* Upload behavior.
* Proxy settings.

### Core configuration

Properties of `CafDocumentDetectorConfig` .

| Property                     | Type                           | Description                                                                                                                           | Default        |
| ---------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `flow`                       | `[CafDocumentDetectorStep]`    | Ordered list of document capture steps.                                                                                               | `[]`           |
| `layout`                     | `CafDocumentDetectorLayout`    | UI customization (buttons, fonts, feedback overlays). Colors are primarily themed by global `CafColorConfiguration`.                  | Default layout |
| `instructionsConfig`         | `CafInstructionsConfiguration` | Customize instructions screen (title, steps, images).                                                                                 | See below      |
| `uploadSettings`             | `CafUploadSettings`            | Controls document upload behavior.                                                                                                    | `enable: true` |
| `manualCaptureEnabled`       | `Bool`                         | Enables manual capture button.                                                                                                        | `true`         |
| `manualCaptureTime`          | `TimeInterval`                 | Timeout (seconds) for manual capture. Use `0` to disable the countdown timer.                                                         | `0`            |
| `requestTimeout`             | `TimeInterval`                 | HTTP request timeout.                                                                                                                 | `60`           |
| `showPopup`                  | `Bool`                         | Shows/hides the initial instruction popup.                                                                                            | `true`         |
| `proxySettings`              | `CafProxySettings?`            | Reverse proxy configuration (host, port, auth).                                                                                       | `nil`          |
| `previewShow`                | `Bool`                         | Enables post-capture preview screen.                                                                                                  | `false`        |
| `ddCustomizations`           | `[CafDDCustomization]?`        | Array of UI string and asset customizations for Document Detector screens (e.g., upload popup, preview screen).                       | `nil`          |
| `enableMultiLanguage`        | `Bool`                         | Enables auto-translation of default messages.                                                                                         | `true`         |
| `allowedPassportCountryList` | `[CafCountryCodes]?`           | Whitelist of allowed passport countries (e.g., `.BR`, `.US`).                                                                         | `nil`          |
| `selectDocumentConfig`       | `CafSelectDocumentConfig?`     | Configures document selection screen (title/description) and per‑document titles/descriptions via `customTitles`/`customDescriptions` | `nil`          |
| `currentStepDoneDelay`       | `TimeInterval`                 | Delay (in seconds) before proceeding after completing a capture step                                                                  | `1.0`          |
| `maxRetryAttempts`           | `Int`                          | Maximum number of retry attempts on server error flow of DocumentCapture.                                                             | `2`            |

### Select Document screen customization (`CafSelectDocumentConfig`)

Use `CafSelectDocumentConfig` to customize the document selection screen. You can set a screen title/description and optionally override the default localized labels per document type.

| Property             | Type                            | Description                                              |
| -------------------- | ------------------------------- | -------------------------------------------------------- |
| `screenTitle`        | `String?`                       | Title shown at the top of the selection screen.          |
| `description`        | `String?`                       | Subtitle/description under the title.                    |
| `customTitles`       | `[CafDocumentTypeKey: String]?` | Override the default title for each document type.       |
| `customDescriptions` | `[CafDocumentTypeKey: String]?` | Override the default description for each document type. |

**Automatic side suffix for two‑sided documents**

When you provide `customTitles` and the flow includes front/back steps for a document type, the SDK automatically appends a localized side suffix to the in‑flow step labels after selection. Single‑step documents that represent an open document (for example, `.rgFull` or `.cnhFull`) receive an "Open" suffix, while other single‑step documents (e.g., `passport`) do not receive a suffix.

Example (two‑sided: RG):

```swift
let titles: [CafDocumentTypeKey: String] = [.rg: "RG (Custom Base Title)"]

var ddConfig = CafDocumentDetectorConfig(
    flow: [
        CafDocumentDetectorStep(stepType: .rgFront),
        CafDocumentDetectorStep(stepType: .rgBack)
    ],
    selectDocumentConfig: CafSelectDocumentConfig(
        customTitles: titles
    )
)

// Resulting step labels (localized):
// "RG (Custom Base Title) - Front"
// "RG (Custom Base Title) - Back"
```

Example (single‑step: Passport; no suffix):

```swift
let titles: [CafDocumentTypeKey: String] = [.passport: "Passport (Custom Base Title)"]

var ddConfig = CafDocumentDetectorConfig(
    flow: [CafDocumentDetectorStep(stepType: .passport)],
    selectDocumentConfig: CafSelectDocumentConfig(customTitles: titles)
)

// Resulting step label:
// "Passport (Custom Base Title)"
```

#### Code example

```swift
let titles: [CafDocumentTypeKey: String] = [
    .rg: "RG (Custom Title)",
    .cnh: "CNH (Custom Title)",
    .passport: "Passport (Custom Title)"
]

let descriptions: [CafDocumentTypeKey: String] = [
    .rgDigital: "RG Digital (Custom Description)",
    .any: "Other (Custom Description)"
]

var ddConfig = CafDocumentDetectorConfig(
    flow: [
        CafDocumentDetectorStep(stepType: .rgFront),
        CafDocumentDetectorStep(stepType: .rgBack)
    ],
    selectDocumentConfig: CafSelectDocumentConfig(
        screenTitle: "Choose a document",
        description: "Select which document you want to use.",
        customTitles: titles,
        customDescriptions: descriptions
    )
)

sdkConfig.setDocumentDetectorConfig(ddConfig)
```

#### Document type keys (`CafDocumentTypeKey`)

Use these keys when customizing labels:

* `rg`
* `rgDigital`
* `cnh`
* `cnhDigital`
* `crlv`
* `rne`
* `ctps`
* `passport`
* `any`

### Instruction screen configuration

Document Detector also supports an instruction screen using `instructionsConfig: CafInstructionsConfiguration`, similar to Face Liveness.

| Property             | Type                           | Description                                        | Default |
| -------------------- | ------------------------------ | -------------------------------------------------- | ------- |
| `instructionsConfig` | `CafInstructionsConfiguration` | Instruction screen content (see properties below). |         |

`CafInstructionsConfiguration`:

| Property                 | Type        | Description                                         | Default |
| ------------------------ | ----------- | --------------------------------------------------- | ------- |
| `enabled`                | `Bool`      | Show/hide the instructions screen.                  | `true`  |
| `captureTitle`           | `String?`   | Header title for capture screen.                    | `nil`   |
| `captureDescriptionText` | `String?`   | Brief description for capture screen.               | `nil`   |
| `captureSteps`           | `[String]?` | Ordered list of instructions for capture.           | `nil`   |
| `captureButtonTitle`     | `String?`   | Text for the confirmation button on capture screen. | `nil`   |
| `captureHeaderImage`     | `UIImage?`  | Image displayed at the top of the capture screen.   | `nil`   |
| `uploadTitle`            | `String?`   | Header title for upload screen.                     | `nil`   |
| `uploadDescriptionText`  | `String?`   | Brief description for upload screen.                | `nil`   |
| `uploadSteps`            | `[String]?` | Ordered list of instructions for upload.            | `nil`   |
| `uploadButtonTitle`      | `String?`   | Text for the confirmation button on upload screen.  | `nil`   |
| `uploadHeaderImage`      | `UIImage?`  | Image displayed at the top of the upload screen.    | `nil`   |

Example:

```swift
let ddConfig = CafDocumentDetectorConfig(
    flow: [
        CafDocumentDetectorStep(stepType: .rgFront),
        CafDocumentDetectorStep(stepType: .rgBack)
    ],
    instructionsConfig: CafInstructionsConfiguration(
        enabled: true,
        captureTitle: "Scan your document",
        captureDescriptionText: "Follow the steps below",
        captureSteps: ["Place the document in frame", "Avoid glare"],
        captureButtonTitle: "Start",
        captureHeaderImage: UIImage(named: "doc_instructions")
    )
)
```

### Layout customization

Properties of `CafDocumentDetectorLayout`. The colors for these elements are primarily influenced by the global `CafColorConfiguration` set in `CafSDKConfiguration`.

| Property                 | Type                        | Description                                           | Default               |
| ------------------------ | --------------------------- | ----------------------------------------------------- | --------------------- |
| `closeButtonImage`       | `UIImage?`                  | Image for the close button.                           | System default        |
| `closeButtonColor`       | `UIColor?`                  | Color of the close button.                            | Global `primaryColor` |
| `closeButtonSize`        | `CGFloat?`                  | Size (width/height) of the close button.              | `44`                  |
| `closeButtonContentMode` | `UIView.ContentMode?`       | Content mode for the close button image.              | `.scaleAspectFit`     |
| `feedbackColors`         | `CafDocumentFeedbackColors` | Colors for feedback overlays (default/error/success). | Predefined colors     |
| `font`                   | `String?`                   | Custom font name (e.g., "Avenir-Bold").               | System font           |

#### Code example:

```swift
var layout = CafDocumentDetectorLayout()
layout.closeButtonImage = UIImage(named: "close_icon")
// layout.primaryColor is no longer available here, use global CafColorConfiguration
layout.font = "Helvetica-Bold"
layout.feedbackColors = CafDocumentFeedbackColors(
    defaultColor: .gray, 
    errorColor: .red, 
    successColor: .green
)
```

### UI String and Asset Customization (`CafDDCustomization`)

The `ddCustomizations` property in `CafDocumentDetectorConfig` allows you to provide an array of objects conforming to `CafDDCustomization` to override default texts and images on specific Document Detector screens.

If a customization object for a particular screen is not provided, or a specific property within that object is `nil`, the SDK will use its default localized strings and assets.

#### `CafPreviewCustomization`

Customizes the document preview screen shown after a document image is captured (if `previewShow` is `true`).

| Property         | Type      | Description                                  | Default (Localized)               |
| ---------------- | --------- | -------------------------------------------- | --------------------------------- |
| `title`          | `String?` | Title text on the preview screen.            | "Is the photo good?"              |
| `message`        | `String?` | Subtitle/message text on the preview screen. | "Check if all info is legible..." |
| `okButton`       | `String?` | Text for the confirmation ("accept") button. | "Yes, it's good!"                 |
| `tryAgainButton` | `String?` | Text for the retry ("take again") button.    | "Take again"                      |

**Example:**

```swift
let previewCustom = CafPreviewCustomization(
    title: "Confirm Photo Quality",
    message: "Ensure all details are clear and there are no reflections.",
    okButton: "Confirm",
    tryAgainButton: "Recapture"
)
// Add to CafDocumentDetectorConfig:
// ddCustomizations: [previewCustom]
```

#### `CafDDUploadCustomization`

Customizes the popup shown when the user chooses to upload a document file.

| Property       | Type       | Description                              | Default (Localized)      |
| -------------- | ---------- | ---------------------------------------- | ------------------------ |
| `image`        | `UIImage?` | Image displayed at the top of the popup. | Default SDK illustration |
| `title`        | `String?`  | Title text of the upload popup.          | "Upload Document"        |
| `message`      | `String?`  | Message text within the upload popup.    | "Select the file..."     |
| `uploadButton` | `String?`  | Text for the "Upload" button.            | "Upload"                 |
| `cancelButton` | `String?`  | Text for the "Cancel" button.            | "Cancel"                 |

**Example:**

```swift
let uploadCustom = CafDDUploadCustomization(
    title: "Select Your Document",
    message: "Please choose the document file you want to upload.",
    uploadButton: "Choose File",
    cancelButton: "Go Back"
)
// Add to CafDocumentDetectorConfig:
// ddCustomizations: [uploadCustom, previewCustom] // Can have multiple customizations
```

#### `CafUploadMessagesCustomization`

Customizes the in-flow quality messages shown during document upload scheduling.

| Property              | Type            | Description                                       | Default (Localized)                      |
| --------------------- | --------------- | ------------------------------------------------- | ---------------------------------------- |
| `sending`             | `String?`       | Message shown when the upload starts.             | `"Sending document... Please wait..."`   |
| `verifyingIntegrity`  | `String?`       | Message shown while verifying document integrity. | `"Verifying document integrity..."`      |
| `processingData`      | `String?`       | Message shown while processing the data.          | `"Processing document data..."`          |
| `almostDone`          | `String?`       | Message shown when upload is nearly complete.     | `"Almost there... Finalizing upload..."` |
| `timeBetweenMessages` | `TimeInterval?` | Interval (in seconds) between each message.       | `15`                                     |

**Example:**

```swift
let messagesCustom = CafUploadMessagesCustomization(
    sending: "Enviando documento...",
    verifyingIntegrity: "Verificando integridade...",
    processingData: "Processando dados...",
    almostDone: "Quase lá!",
    timeBetweenMessages: 20
)
// Add to CafDocumentDetectorConfig:
// ddCustomizations: [messagesCustom]
```

#### `CafFailedPhotoCustomization`

Customizes the failure screen shown when a photo fails to send.

| Property         | Type      | Description                                 | Default |
| ---------------- | --------- | ------------------------------------------- | ------- |
| `title`          | `String?` | Title text displayed on the failure screen. |         |
| `description`    | `String?` | Description text explaining the failure.    |         |
| `continueButton` | `String?` | Text for the retry button.                  |         |

**Example:**

```swift
let failedPhotoCustom = CafFailedPhotoCustomization(
    title: "Foto não enviada!",
    description: "Não foi possível enviar a foto. Verifique sua conexão.",
    continueButton: "Tentar novamente"
)
// Add to CafDocumentDetectorConfig or UploadValidationViewController:
// ddCustomizations: [failedPhotoCustom]
```

#### `CafMessageCustomization`

Customizes various in-flow messages displayed during the document capture process (e.g., sensor messages, AI feedback).

| Property                         | Description                                         | Default (Localized)               |
| -------------------------------- | --------------------------------------------------- | --------------------------------- |
| `waitMessage`                    | Shown during SDK initialization.                    | "Wait"                            |
| `holdDocumentMessage`            | Shown when asking user to hold the document steady. | "Hold the document"               |
| `fitTheDocumentMessage`          | Advises aligning document to the mask.              | "Fit the document in the marking" |
| `verifyingQualityMessage`        | Shown during quality check.                         | "Verifying quality…"              |
| `lowQualityDocumentMessage`      | Shown on capture failure due to quality.            | "Oops, try again"                 |
| `uploadingImageMessage`          | Shown during image upload.                          | "Uploading image..."              |
| `sensorLuminosityMessage`        | Low brightness warning.                             | "Environment too dark"            |
| `manualCaptureMessage`           | Text for manual capture button.                     | "Manual Capture"                  |
| `sensorOrientationMessage`       | Device orientation warning.                         | "Phone is not horizontal"         |
| `sensorStabilityMessage`         | Device stability warning.                           | "Keep the phone steady"           |
| `popupDocumentSubtitleMessage`   | Subtitle for the initial instruction popup.         | Default instruction subtitle      |
| `passportCountryNotValidMessage` | Shown if selected passport country is not valid.    | "Selected country is not valid"   |
| `passportCountryLoadingMessage`  | Shown while loading passport country data.          | "Loading countries..."            |
| `aiScanDocumentMessage`          | Prompt to scan a document (AI).                     | "Scan a document"                 |
| `aiGetCloserMessage`             | Prompt to move closer (AI).                         | "Get closer to the document"      |
| `aiCentralizeMessage`            | Prompt to center the document (AI).                 | "Center the document"             |
| `aiMoveAwayMessage`              | Prompt to move farther away (AI).                   | "Move away from the document"     |
| `aiAlignDocumentMessage`         | Prompt to align the document (AI).                  | "Align the document"              |
| `aiTurnDocumentMessage`          | Prompt to turn/rotate the document (AI).            | "Turn the document"               |
| `aiCapturedMessage`              | Confirmation of successful capture (AI).            | "Capturing the document"          |

**Example:**

```swift
let messageCustom = CafMessageCustomization(
    waitMessage: "Please wait...",
    fitTheDocumentMessage: "Align your document within the frame."
)
// Add to CafDocumentDetectorConfig:
// ddCustomizations: [messageCustom, previewCustom, uploadCustom]
```

## Document capture flow

Properties of `CafDocumentDetectorStep`.

| Property              | Type                  | Description                                                            | Required | Default                         |
| --------------------- | --------------------- | ---------------------------------------------------------------------- | -------- | ------------------------------- |
| `stepType`            | `CafDocumentStepType` | Document type to capture (e.g., `.rgFront`).                           | Yes      |                                 |
| `customStepLabel`     | `String?`             | Text shown at the bottom of the screen for this step.                  | No       | Document's default label        |
| `customIllustration`  | `UIImage?`            | Image shown in the instruction popup for this step.                    | No       | Document's default illustration |
| `showStepLabel`       | `Bool`                | Toggles visibility of the step label.                                  | No       | `true`                          |
| `customMessage`       | `String?`             | Custom message text for the instruction popup of this step.            | No       | Document's default message      |
| `customOkButtonTitle` | `String?`             | Custom text for the 'OK' button in the instruction popup of this step. | No       | "OK" (localized)                |

#### Code example:

```swift
    let step = CafDocumentDetectorStep(
        stepType: .rgFront,
        customStepLabel: "Front of ID",
        customIllustration: UIImage(named: "id_front_icon"),
        customMessage: "Please place the front of your ID card in the frame.",
        customOkButtonTitle: "Got it!"
    )
```

## Upload customization

Properties of `CafUploadSettings`.

| Property          | Type           | Description                               | Default        |
| ----------------- | -------------- | ----------------------------------------- | -------------- |
| `enable`          | `Bool`         | Enables document upload functionality.    | `true`         |
| `compress`        | `Bool`         | Compresses files before upload.           | `true`         |
| `fileFormats`     | `[FileFormat]` | Allowed formats: `.png`, `.jpeg`, `.pdf`. | All formats    |
| `maximumFileSize` | `Int`          | Max file size in KB.                      | `10000` (10MB) |

#### Code example:

```swift
let uploadSettings = CafUploadSettings(
    enable: true,
    fileFormats: [.jpeg, .pdf],
    maximumFileSize: 5000
)
```

## Proxy customizations

Properties of `CafProxySettings`.

| Property   | Type      | Description                     | Required |
| ---------- | --------- | ------------------------------- | -------- |
| `hostname` | `String`  | Proxy host (e.g., "proxy.com"). | Yes      |
| `port`     | `Int`     | Proxy port (e.g., `8080`).      | Yes      |
| `user`     | `String?` | Authentication username.        | No       |
| `password` | `String?` | Authentication password.        | No       |

#### Code example:

```swift
let proxy = CafProxySettings(hostname: "my.proxy.io", port: 443)
```

## Supported documents in Document Detector

Use these static values of `CafDocumentStepType` (which internally map to `CafDocument`):

| Document Type | Description                                   |
| ------------- | --------------------------------------------- |
| `.rgFront`    | Front of Brazilian ID (RG)                    |
| `.rgBack`     | Back of Brazilian ID (RG)                     |
| `.rgFull`     | Brazilian ID (opened, showing front and back) |
| `.cnhFront`   | Front of Brazilian Driver's License (CNH)     |
| `.cnhBack`    | Back of Brazilian Driver's License (CNH)      |
| `.cnhFull`    | Brazilian Driver's License (opened)           |
| `.crlv`       | Brazilian Vehicle Registration (CRLV)         |
| `.rneFront`   | Front of Brazilian Foreigner ID (RNE)         |
| `.rneBack`    | Back of Brazilian Foreigner ID (RNE)          |
| `.ctpsFront`  | Front of Brazilian Work Card (CTPS)           |
| `.ctpsBack`   | Back of Brazilian Work Card (CTPS)            |
| `.passport`   | Passport (any country)                        |
| `.any`        | Generic document (no specific validation)     |

**Note:** All enum cases are in camelCase (e.g., use `.rgFront` instead of `.RG_FRONT`)

#### Code example:

```swift
var layout = CafDocumentDetectorLayout()
// Primary color is set globally via CafColorConfiguration
layout.closeButtonImage = UIImage(named: "close")

let previewCustomization = CafPreviewCustomization(title: "Check Photo", okButton: "Looks Good")
let uploadCustomization = CafDDUploadCustomization(uploadButton: "Select File")
let messageCustomization = CafMessageCustomization(waitMessage: "Please Wait...")

let config = CafDocumentDetectorConfig(
    flow: [
        CafDocumentDetectorStep(stepType: .rgFront, customMessage: "Place the front of your RG here."),
        CafDocumentDetectorStep(stepType: .rgBack)
    ],
    layout: layout,
    uploadSettings: CafUploadSettings(enable: true),
    proxySettings: CafProxySettings(hostname: "proxy.example.com", port: 8443),
    ddCustomizations: [previewCustomization, uploadCustomization, messageCustomization]
)
```

## Technical Support and Usage Tips

For more details and advanced usage scenarios, refer to the following resources:

* **GitHub Repository:** access the source code, issue tracking, and release notes in the [CafSDK GitHub repository](https://github.com/combateafraude/caf-ios-sdk).
* **FAQs and Troubleshooting**: check our FAQ section for common issues and troubleshooting tips.
* **Support**: for additional assistance, contact our support team or join our developer community forum.

We continuously update the documentation as new features and improvements are released. Stay up to date for future updates!

***

## Release notes

## CafSDK iOS v6.4.2

### Analytics improvements

* **Improved payload quality:** Analytics now include richer and more standardized metadata across capture flows.

### Security Enhancements

* **`securityEnabled` flag on `CafSDKConfiguration`:** Added a new `securityEnabled: Bool = false` property to `CafSDKConfiguration`, allowing security enforcement to be toggled programmatically. When set to `true`, the SDK performs strict security validation during initialization and execution; if a security violation is detected, the SDK throws a `securityException` and terminates the flow.

  **Code example:**

  ```swift
  let sdkConfig = CafSDKConfiguration(
      presentationOrder: [.faceLiveness, .documentDetector],
      securityEnabled: true
  )
  ```
* **`CAFEnforceSecurity` removed:** The `CAFEnforceSecurity` `Info.plist` flag is no longer read by the SDK. Security enforcement is now controlled exclusively through the new `securityEnabled` property on `CafSDKConfiguration`. Existing integrations relying on the Info.plist flag must migrate to set `securityEnabled` programmatically.

### Bug fixes

* **Document Detector — RG flow:** Fixed issues affecting the RG document capture flow in `DocumentDetector`.

## CafSDK iOS v6.3.0

### Architecture updates

* **KMP/CafSolutions dependency removal:** The liveness provider stack no longer depends on `CafSolutions`.

### Analytics improvements

* **Improved payload quality:** Analytics now include richer and more standardized metadata.

## CafSDK iOS v6.2.0

{% hint style="warning" %}
Versions earlier than 6.2.0 will result iProov Liveness to become inoperable as of March 12, 2026. To ensure proper functionality and service continuity, please use version 6.2.0 or later.
{% endhint %}

### Breaking Changes

* **Minimum iOS version updated:** The SDK now requires **iOS 15.0+**.

### Updates

* **Dependency update:** iProov dependency updated to **13.1.0**.
* **New Failure Options:** Added new failure cases to `CafFailureType` for better failure handling:
  * `eyewear`
  * `faceNotFound`
  * `framesBlurry`
  * `lightingIssues`
  * `motionIssue`
  * `backgroundIssue`
  * `deviceIssue`
  * `deviceRestart`
  * `systemError`
  * `rejected`
  * `timeout`
  * `userNotFound`
  * `processingFault`

### Important Notice

* **Reverse proxy deprecation warning:** Reverse proxy support will be discontinued in a future release. A necessary iProov-related update is required to keep iProov working properly and prevent certificate issues. **After March 15, 2026, Faceliveness and Faceauth services could be unavailable.**

## CafSDK iOS v6.1.0

### New Features

* **Advanced Analytics Integration:** Updated analytics implementation.

## CafSDK iOS v6.0.0

### Breaking Changes

* **`CafInstructionsConfiguration` property renaming:** The following properties have been renamed to support both capture and upload instruction screens:
  * `title` → `captureTitle`
  * `descriptionText` → `captureDescriptionText`
  * `steps` → `captureSteps`
  * `buttonTitle` → `captureButtonTitle`
  * `headerImage` → `captureHeaderImage`
  * New properties added: `uploadTitle`, `uploadDescriptionText`, `uploadSteps`, `uploadButtonTitle`, `uploadHeaderImage`

### Security Enhancements

* **Runtime Protection:** Implemented comprehensive checks for dynamic instrumentation, and security improvements.
* **New Error Type:** Added `securityException` to `CafErrorType`. The SDK will now immediately terminate the flow and return this error if a security violation is detected during initialization or execution.

## CafSDK iOS v5.7.0

### New Features

* **Session pre-loading for Face Liveness:**
  * `CafSDKProvider` now exposes `loadSession()` to pre-load the Face Liveness session before calling `start()`.
  * While a pre-load is running, the unified callback emits `.loading` and `.loaded` events, allowing you to update the UI accordingly.

### Document Detector

* **Analytics enhancements:**
  * New analytics fields were added to better understand document capture behaviour.
* **Flow validation and error handling:**
  * If `CafDocumentDetectorConfig.flow` is empty, the SDK now fails fast with a `libraryException` instead of starting the capture flow.
  * Attestation and token validation now distinguish between network errors, invalid tokens and invalid responses.

### Behaviour Changes

* **Manual capture defaults:**
  * `manualCaptureTime` in `CafDocumentDetectorConfig` now defaults to `0` seconds (no countdown). Manual capture can still be configured explicitly via `manualCaptureEnabled` and `manualCaptureTime`.

## CafSDK iOS v5.6.2

### New Features

* **Face Authentication Error Handling:** Added a new `faceAuthentication` case to `CafErrorType` to specifically handle backend errors when `executeFaceAuth` is enabled.

### Updates

* **Analytics:** Improved Analytics validation.

## CafSDK iOS v5.5.1

### Bug fixes

* **CafFaceliveness:** Fixing CafFaceliveness try again flow.

### Updates

* Downgrading Fingerprint `2.7.0` > `2.6.0` due to compatibility issues, will be updated in future versions.

## CafSDK iOS v5.5.0

### New Features

* **PayFace (Fortface) Provider Integration:** Optional Face Liveness provider now available.
  * SPM product: `FortfaceProvider`
  * CocoaPods subspec: `CafSDKiOS/FortfaceProvider`
* **Generic Face Liveness Customizations:** New `flCustomizations` property on `CafFaceLivenessConfig` with `CafFLPayFaceCustomization` to customize PayFace UI texts and font.
* **Document Side Suffix for Custom Titles**: When using `customTitles` in `CafSelectDocumentConfig`, the SDK now automatically appends a localized suffix (e.g., "Front"/"Back") for documents that have two sides.

### Updates

* Getting started examples updated to include optional Fortface provider and `flCustomizations` usage.

## CafSDK iOS v5.4.4

### New Features

* Document selection labels customization: you can now override per‑document titles and descriptions on the select‑document screen via `CafSelectDocumentConfig.customTitles` and `customDescriptions` using `CafDocumentTypeKey` keys. This affects both the selection list and the step labels applied after selection.

## CafSDK iOS v5.4.3

### Improvements

* Normalized error and failure messages: callbacks now surface cleaner, human‑readable descriptions by extracting nested messages from JSON payloads when available
* Failure screen presentation is now full-screen for consistency

## CafSDK iOS v5.4.2

### Bug fixes

* Completion reliability when no modal is presented: providers now guarantee callbacks even when instruction/transition screens are disabled and no view controller is presented
* Safer dismissal logic in both Face Liveness and Document Detector providers to avoid missed callbacks or stuck UI in edge cases

## CafSDK iOS v5.4.1

### Improvements

* Document upload validation: clearer feedback for PDF files, including explicit messages when a file is encrypted, locked, or unreadable
* More consistent cancellation behavior during document upload

### Fixes

* Flow completion reliability when transition screens are disabled: sessions now finalize correctly and callbacks are delivered in both batched and non-batched modes
* Document selection now preserves the configured document order when confirming multiple selections

## CafSDK iOS v5.4.0

### New Features

* **Enhanced Transition Screen Control:** Added `enableTransitionScreens` parameter to `CafSDKConfiguration` to control whether transition screens are displayed between modules
  * When set to `true` (default), confirmation screens are shown between modules
  * When set to `false`, modules execute sequentially without intermediate screens for a streamlined experience
* **Improved Error Handling:** Enhanced error management and standardization across all modules
  * Better error categorization with standardized error types
  * Improved analytics for error tracking and debugging
* **Advanced Analytics Integration:** Updated analytics system with comprehensive tracking capabilities
  * Improved error analytics with standardized error parameters
  * Better session and entrypoint tracking

### Updates

* **Token Validation:** Enhanced token validation with better error messages for empty tokens and person IDs

### Code Example

```swift
let sdkConfig = CafSDKConfiguration(
    presentationOrder: [.faceLiveness, .documentDetector],
    colorConfig: CafColorConfiguration(
        primaryColor: "#FF0000",
        secondaryColor: "#FFFFFF",
        contentColor: "#000000",
        backgroundColor: "#FFFFFF",
        mediumColor: "#CCCCCC",
        dialogBackgroundColor: "#FFFFFF",
        dialogBorderColor: "#E5E5E7"
    ),
    waitForAllServices: true,
    enableTransitionScreens: true // New parameter
)
```

## CafSDK iOS v5.3.0

### New Features

* **Enhanced Dialog Customization:** Added new color configuration properties to customize dialog and popup appearances:
  * `dialogBackgroundColor`: Customize the background color of dialogs and popups (defaults to dynamic color based on interface style: `#1C1C1E` for dark mode, `#FFFFFF` for light mode)
  * `dialogBorderColor`: Customize the border color of dialogs and popups (defaults to `#E5E5E7`)

### Code Example

```swift
let colorConfig = CafColorConfiguration(
    primaryColor: "#FF0000",
    secondaryColor: "#FFFFFF",
    contentColor: "#000000",
    backgroundColor: "#FFFFFF",
    mediumColor: "#CCCCCC",
    dialogBackgroundColor: "#FFFFFF", // New
    dialogBorderColor: "#E5E5E7"      // New
)
```

## CafSDK iOS v5.2.0

### New Features

* **Enhanced Document Flow Logic:** When digital documents (RG Digital or CNH Digital) are present in the flow, the SDK now automatically:
  * Forces upload mode to be enabled
  * Skips the photo source selection screen
  * Goes directly to the upload flow for a streamlined user experience

### Updates

* **Upload Settings Default Changed:** `CafUploadSettings.enable` now defaults to `true` instead of `false`
  * This affects `CafDocumentDetectorConfig`, `CafUploadSettings`
* **Document Selection Logic:** Enhanced logic for RG and CNH document selection:
  * When both front/back and full documents are available, the SDK intelligently selects front and back documents in the correct order
  * Digital document options are prioritized and displayed first in selection screens

### Fixes

* **Upload flow:** Fixed an issue related to incorrect documents leading to an error in the upload flow.

## CafSDK iOS v5.1.0

### Updates

* Security Improvements on both DocumentDetector and CafFaceliveness
* New Parameter `maxRetryAttempts` on DocumentDetector to set the maximum retry attempts on server error flow of DocumentCapture (the default is `2`)

### Fixes

* CafSDKProvider error initialization, both `mobileToken` and `personId` are required

## CafSDK iOS v5.0.2

### Updates

* Xcode build version update from `16.2` to `16.4`.

## CafSDK iOS v5.0.1

### Updates

* Updated `Iproov` version from `12.3.0` to `12.3.1`.

### New Features

* Updated `reverseProxyConfig: CafReverseProxyConfig` to **CafFaceLivenessConfig**, consolidating `authBaseUrl`, `livenessBaseUrl`, and `certificates` parameters.
* New `executeFaceAuth` parameter added to define whether face authentication should be performed.
* New `maxRetryAttempts` method for `CafFaceLivenessConfig` to set the maximum number of retry attempts for face liveness validation.

## CafSDK iOS v4.1.1

### Improvements

* Improvements for hibrid analytics (`Flutter / React Native`)

## CafSDK iOS v4.1.0

### New Features

* Added `customLocalization: String?` to **FaceLiveness** builders.
* New customization types for DocumentDetector:
  * `CafUploadMessagesCustomization`
  * `CafFailedPhotoCustomization`

## CafSDK iOS v4.0.0

### Major Changes

* **Unified Response API:** `CafUnifiedResponse` now exposes only `signedResponse: String` (no more `[String: Any]` result dictionary).
* **Error Handling:** Added `invalidResponseException` to `CafErrorType`;
* **Breaking Changes:**
  1. `CafUnifiedResponse` initializer signature changed: no `result` parameter.
  2. Property `result` removed; replace all uses with `signedResponse`.
* **Updated Retry on document upload:** in slower connections or interrupted uploads, the documentDetector flow integrated a retry option for document upload

**Migration Guide from v3.x**

1. **Update Dependency**
   * SPM: use `from: "4.0.0"`
   * CocoaPods: `pod 'CafSDKiOS', '~> 4.0.0'`
2. **Callback Handling**

   ```swift
   case .success(let responses):
       responses.forEach { response in
           print("Module: \(response.moduleName) SignedResponse: \(response.signedResponse)")
       }
   ```
3. **Remove** `response.result`
   * All references to the `[String: Any]` result map should use response.`signedResponse` instead.
4. **Handle** `invalidResponseException`
   * In your `.error` switch, add a case for `.invalidResponseException`.
5. Document Detector Flows
   * If you relied on the old result dictionary, migrate to parsing your JWT from `signedResponse`.

## CafSDK iOS v3.0.0

### New Features

* **Improved Analytics**
* **Failure Event Handling:** Added detailed `failure` case to `CafUnifiedEvent` with server response, error type and description
* **Document Detector UI Customization:**
  * Introduced `CafDDCustomization` protocol and concrete types (`CafPreviewCustomization`, `CafDDUploadCustomization`, `CafMessageCustomization`) to allow overriding default texts and images on specific Document Detector screens (e.g., preview, upload popup, in-flow messages). This is configured via the new `ddCustomizations` property in `CafDocumentDetectorConfig`.
  * `CafDocumentDetectorStep` now includes `customMessage` and `customOkButtonTitle` properties to customize the instruction popup for each step.
* **Theming Update:**
  * Document Detector specific color properties (like `primaryColor`, `uploadBackGroundColor`, `previewBackGroundColor`) have been removed from `CafDocumentDetectorLayout`. The UI now primarily inherits its theme from the global `CafColorConfiguration` set in `CafSDKConfiguration`, ensuring a more consistent look and feel.

### Updates

* Improved error handling differentiation:
  * Use `CafFailureType` enum type for SDK module-specific operational failures
  * Use `CafErrorType` enum type for general execution errors

### Breaking Changes

1. **Event Signature Updates:**

```swift
case .failure(response: String?, type: CafFailureType, description: String?)
case .error(type: CafErrorType, description: String)  // Replaces old String-based error
```

2. **Type Safety Enforcement:**

* All error/failure type comparisons must use enum cases instead of raw strings

3. **`CafDocumentDetectorConfig` Changes:**
   * Removed `previewTitle`, `previewSubtitle`, `previewConfirmLabel`, `previewRetryLabel` properties. Use `CafPreviewCustomization` within `ddCustomizations` instead.
   * Removed `messageSettings` property. Use `CafMessageCustomization` within `ddCustomizations` instead.
4. **`CafDocumentDetectorLayout` Changes:**
   * Removed `primaryColor`, `uploadBackGroundColor`, `previewBackGroundColor` properties. Colors are now themed globally via `CafColorConfiguration`.

### Migration Guide

1. Update to v3.0.0+.
2. Include new `.failure`event

```swift
case .failure(response: String?, type: CafFailureType, description: String?)
```

3. Update `.error` event

```swift
case .error(type: CafErrorType, description: String)  // Replaces old String-based error
```

4. **Update `CafDocumentDetectorConfig`:**
   * If you were using `previewTitle`, `previewSubtitle`, etc., create a `CafPreviewCustomization` object, set its properties, and add it to the `ddCustomizations` array in `CafDocumentDetectorConfig`.
   * If you were using `messageSettings`, create a `CafMessageCustomization` object, set its properties, and add it to the `ddCustomizations` array.
5. **Update `CafDocumentDetectorStep`:**
   * If you need to customize the instruction popup message or OK button text for a specific step, use the new `customMessage` and `customOkButtonTitle` initializers/properties of `CafDocumentDetectorStep`.
6. **Review Theming:**
   * Ensure your global `CafColorConfiguration` (in `CafSDKConfiguration`) is set up as desired, as Document Detector UI elements will now primarily use these colors.

## CafSDK iOS v2.0.0

### New Features

* **Batch Results Flag:** `CafSDKConfiguration(waitForAllServices: true)` now aggregates all module responses into a single `.success(responses: [...])`.
* **Unified `.success` Update:** `.success` now always carries an array of responses.

### Breaking Changes

* Signature of `CafUnifiedEvent.success` changed to `success(responses: [CafUnifiedResponse])`.

### Migration Guide

1. Update to v2.0.0+.
2. Change handler to expect an array:

   ```
   case .success(let responses):
       responses.forEach { resp in /* ... */ }
   ```

## CafSDK iOS v1.4.0

### New Features

* **Introducing `CafSDKProvider`:** A unified entry point for integrating Face Liveness and Document Detector modules with a single configuration.
* **Builder Pattern:** Simplified initialization using `CafSDKProvider.Builder` for modular, type-safe setup.
* **Unified Configuration:** Configure both modules using `CafSDKConfiguration`, including execution order (`presentationOrder`) and UI theming (`CafColorConfiguration`).
* **Cross-Module Consistency:** Shared authentication, environment, and logging across modules.

### Documentation Updates

* Revised guides for Swift Package Manager (SPM) and CocoaPods integration.
* Added detailed examples for `CafFaceLivenessConfig` and `CafDocumentDetectorConfig`.

### Configuration Enhancements

#### Face Liveness

* Customize instructions (`CafInstructionsConfiguration`).
* Configure reverse proxy endpoints (`authBaseUrl`, `livenessBaseUrl`).

#### Document Detector

* Define multi-step capture flows (`[CafDocumentDetectorStep]`).
* UI customization (`CafDocumentDetectorLayout`, `CafMessageSettings`).
* Proxy support (`CafProxySettings`).

### Breaking Changes

* **New integration Module:** `CafSDK`
* **Module Renaming:** `FaceLiveness` → `CafFaceLiveness`, `DocumentDetector` → `CafDocumentDetector`
* **Updated Dependencies:** Requires Xcode 16.2+ and iOS 13.0+

### Migration Guide

1. Replace standalone module initializers with `CafSDKProvider`
2. Update enum cases to lowercase (e.g., `.CNH_FRONT` → `.cnhFront`)
3. Use `CafDocumentDetectorStep(stepType:)` instead of legacy constructors


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.caf.io/caf-sdk/ios/getting-started-with-the-sdk-5.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
