> 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/flutter/getting-started-with-the-sdk.md).

# Getting Started with the SDK

## About CafSDK

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

CafSDK is a unified SDK that integrates multiple modules for identity verification: **Face Liveness (FL)** and **Document Detector (DD)**, executed sequentially with a unified configuration interface.

### What is Face Liveness

Face Liveness is the module that validates the authenticity of a face captured by a photo application, ensuring that the image corresponds to a real person and not a spoofing attempt.

**Technical characteristics:**

* URL configuration for authentication (`authBaseUrl`) and liveness verification (`livenessBaseUrl`)
* Support for reverse proxy configuration with certificate pinning
* Flags to enable screen capture and debug mode
* Configurable retry attempts and face authentication execution
* Support for multiple authentication providers

### What is Document Detector

Document Detector 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 `CafDocumentDetectorFlow` for document capture
* Support for multiple document types (RG, CNH, Passport, etc.)
* Operational parameters, such as timeout, manual capture flags, and other settings
* Possibility of using the camera for framing validations, or document file upload
* Advanced customization options for UI, messages, and behavior

***

## Example

Check out the [example app](https://github.com/combateafraude/caf-sdk-flutter-exemple) for a complete implementation example.

***

## Installation

### Requirements

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

#### Flutter

| Requirement         | Version |
| ------------------- | ------- |
| **Flutter Version** | 3.3.0+  |
| **Dart**            | 3.9.0+  |

#### Android

| Requirement                                        | Version |
| -------------------------------------------------- | ------- |
| **Android SDK API - minimum version (minSdk)**     | 26      |
| **Android SDK API - compile version (compileSdk)** | 36+     |
| **Kotlin**                                         | 1.8+    |
| **Gradle**                                         | 8.0+    |
| **Android Gradle Plugin (AGP)**                    | 8.0+    |

#### iOS

| Requirement               | Version |
| ------------------------- | ------- |
| **iOS Deployment Target** | 13.0+   |
| **Xcode**                 | 14.0+   |
| **Swift**                 | 5.0+    |

### Step 1: Install the SDK

Install the main SDK package:

```sh
flutter pub add caf_sdk
```

### Step 2: Configure Module Selection

Create a `caf-modules-config.json` file in your project root to specify which modules to include:

> **Note**: If you omit this file, all modules are enabled by default and **`iproov-lite`** is used as the default Face Liveness provider.

```json
{
  "documentDetector": true,
  "faceLiveness": true,
  "documentDetectorUI": true,
  "faceLivenessUI": true,
  "livenessProviders": "iproov-lite"
}
```

Set to `true` the modules you want to use in your application.

For a single provider, `livenessProviders` can be a string. Allowed values are `iproov-lite`, `iproov-full`, `payface`, and `facetec`. To use several providers, use an array (see the example below).

```json
{
  "documentDetector": true,
  "faceLiveness": true,
  "documentDetectorUI": true,
  "faceLivenessUI": true,
  "livenessProviders": [
    "iproov-lite",
    "payface",
    "facetec"
  ]
}
```

**iProov and Protobuf**

* **`iproov-lite`**: use when your app targets **Protobuf JavaLite**—the usual choice for a smaller binary footprint on Android.
* **`iproov-full`**: use when you need **Protobuf Java** (full) together with iProov.

You can declare **more than one** provider by setting `livenessProviders` to an array when your integration requires it.

{% hint style="warning" %}
If you include the **PayFace** provider, you must also use **iProov Lite** (`iproov-lite`). PayFace is built against Protobuf JavaLite; mixing it with **`iproov-full`** causes Protobuf dependency conflicts at build time.
{% endhint %}

Set to `true` the modules you want to use in your application.

### Step 3: Android Configuration

#### Add Maven Repositories

Configure the project's `build.gradle.kts` file (usually located at the root level):

```kotlin
repositories {
    // Caf Repository
    maven { url = uri("https://repo.combateafraude.com/android/release") }
    
    // iProov Repository (required for Face Liveness)
    maven { url = uri("https://raw.githubusercontent.com/iProov/android/master/maven/") }
    
    // FingerPrintJS Repository
    maven { setUrl("https://maven.fpregistry.io/releases") }
    
    // JitPack
    maven { setUrl("https://jitpack.io") }

    // Fortface Repository - required to use the PayFace provider
    maven {
        url = uri("https://cdn-fortface-sdk.fortface.com.br")
        credentials(HttpHeaderCredentials::class) {
            name = "X-Sdk"
            value = "CAF"
        }
        authentication {
            create<HttpHeaderAuthentication>("header")
        }
    }
}
```

### Step 4: iOS Configuration

Navigate to the `ios/` directory of your Flutter project and run:

```sh
pod install
```

* This step is mandatory for iOS to correctly link the native modules and their required dependencies.
* Always re-run `pod install` whenever native dependencies are added or updated.

***

## Permissions

### Android

For the modules to operate correctly, you must declare the following permissions in your **AndroidManifest.xml**:

**For Face Liveness**

| Permission                    | Description                                                                             | Necessity |
| ----------------------------- | --------------------------------------------------------------------------------------- | --------- |
| `android.permission.CAMERA`   | Allows access to the camera to capture images and perform face verification (liveness). | Mandatory |
| `android.permission.INTERNET` | Allows communication with authentication and verification services (HTTPS/WSS).         | Mandatory |

**For Document Detector**

| Permission                                 | Description                                                                 | Necessity        |
| ------------------------------------------ | --------------------------------------------------------------------------- | ---------------- |
| `android.permission.CAMERA`                | Allows access to the camera to capture document images.                     | Only for capture |
| `android.permission.INTERNET`              | Allows captured images to be sent to servers for processing and validation. | Mandatory        |
| `android.permission.READ_EXTERNAL_STORAGE` | Allows access to stored files and images for processing, if necessary.      | Only for upload  |

### iOS

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

**For Face Liveness:**

| Permission                 | Description                                                                             | Necessity |
| -------------------------- | --------------------------------------------------------------------------------------- | --------- |
| `NSCameraUsageDescription` | Allows access to the camera to capture images and perform face verification (liveness). | Mandatory |
| `Network access`           | Allows communication with authentication and verification services (HTTPS/WSS).         | Mandatory |

**For Document Detector:**

| Permission                       | Description                                                                 | Necessity        |
| -------------------------------- | --------------------------------------------------------------------------- | ---------------- |
| `NSCameraUsageDescription`       | Allows access to the camera to capture document images.                     | Only for capture |
| `Network access`                 | Allows captured images to be sent to servers for processing and validation. | Mandatory        |
| `NSPhotoLibraryUsageDescription` | Allows access to stored files and images for processing, if necessary.      | Only for upload  |

***

## Basic Implementation

### Simple Example

Here's a basic implementation example:

```dart
import 'dart:async';
import 'package:caf_sdk/types/index.dart';
import 'package:flutter/material.dart';
import 'package:caf_sdk/caf_sdk.dart';

void main() => runApp(const App());

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CAF SDK Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const SimpleExamplePage(),
    );
  }
}

class SimpleExamplePage extends StatefulWidget {
  const SimpleExamplePage({super.key});

  @override
  State<SimpleExamplePage> createState() => _SimpleExamplePageState();
}

class _SimpleExamplePageState extends State<SimpleExamplePage> {
  final _cafSdk = CafSdk();
  StreamSubscription<CafResponse>? _eventSubscription;

  @override
  void initState() {
    super.initState();
    _initializeEventStream();
  }

  @override
  void dispose() {
    _eventSubscription?.cancel();
    super.dispose();
  }

  void _initializeEventStream() {
    _eventSubscription = _cafSdk.eventStream.listen((event) {
      if (!mounted) return;

      if (event.success != null) {
        print('Success: ${event.success!.moduleName} -> ${event.success!.signedResponse}');
      } else if (event.error != null) {
        print('Error: ${event.error!.type} - ${event.error!.description}');
      } else if (event.failure != null) {
        print('Failure: ${event.failure!.type} - ${event.failure!.description}');
      }
    });
  }

  Future<void> _initialize() async {
    try {
      // SDK Configuration
      final config = CafSdkConfiguration(
        mobileToken: 'token',
        personId: 'personId',
        environment: CafEnvironment.dev,
        configuration: CafSdkBuilderConfiguration(
          presentationOrder: [
            CafModuleType.faceLiveness,
            CafModuleType.documentDetector,
          ],
          enableSecurityModule: true,
          waitForAllServices: true,
        ),
      );

      // Face Liveness Configuration
      final faceLivenessConfig = CafFaceLivenessConfiguration(
        loading: true,
        debugModeEnabled: true,
        payFaceDebugMode: false,
      );

      // Document Detector Configuration
      final documentDetectorConfig = CafDocumentDetectorConfiguration(
        flow: [
          CafDocumentDetectorFlow(document: CafDocument.rgFront),
          CafDocumentDetectorFlow(document: CafDocument.rgBack),
        ],
        uploadSettings: CafDocumentDetectorUploadSettings(enable: false),
        manualCaptureEnabled: false,
        manualCaptureTime: 45,
        showPopup: true,
        previewShow: false,
        securitySettings: CafDocumentDetectorSecuritySettings(
          useAdb: true,
          useDebug: true,
          useDevelopmentMode: true,
        ),
      );

      await _cafSdk.initializeCafSdk(
        cafSdkConfiguration: config,
        faceLivenessConfiguration: faceLivenessConfig,
        documentDetectorConfiguration: documentDetectorConfig,
      );
    } catch (e) {
      print('Error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('CAF SDK Simple Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Center(
                child: ElevatedButton(
                  onPressed: _initialize,
                  child: Text('Start')
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```

***

## Configuration

### Language

#### Android

The language is automatically set according to the language configured on the device without any additional settings.

#### iOS

According to Apple's documentation, configuring `Localizations` and `CFBundleLocalizations` should be done in Xcode:

[Adding support for languages and regions](https://developer.apple.com/documentation/xcode/adding-support-for-languages-and-regions)

[CFBundleLocalizations](https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundlelocalizations)

After these settings, the SDK will recognize the device's language.

### Global Configuration

The `CafSdk` class serves as the central container for all configurations. This configuration defines the execution order of the modules and the visual identity.

**Essential parameters:**

* **mobileToken**: Token that authenticates the request and ensures that only authorized clients start the flow
* **personId**: Unique user identifier for which the flow will be executed
* **environment**: Defines the execution environment (PROD, BETA, DEV)
* **presentationOrder**: Defines the sequence in which the modules will be executed
* **enableSecurityModule**: Enables or disables the security module. Optional, default is `true`

**Code example for creating the global configuration:**

```dart
final _cafSdk = CafSdk();

// SDK Configuration
final config = CafSdkConfiguration(
  mobileToken: "mobile-token",
  personId: "person-id",
  environment: CafEnvironment.prod,
  configuration: CafSdkBuilderConfiguration(
    presentationOrder: [
      CafModuleType.faceLiveness,    // or CafModuleType.faceLivenessUi
      CafModuleType.documentDetector // or CafModuleType.documentDetectorUi
    ],
    enableSecurityModule: true,       // Optional, default is true
    waitForAllServices: true,         // Optional, default is true
    enableTransitionScreens: true,    // Optional, default is true
    colorConfiguration: CafColorConfiguration(
      primaryColor: "#0000FF",
      secondaryColor: "#00FF00",
      backgroundColor: "#FFFFFF",
      contentColor: "#000000",
      mediumColor: "#CCCCCC",
      dialogBackgroundColor: "#FFFFFF",
      dialogBorderColor: "#E5E5E7",
    ),
  ),
);

// Initialize the SDK
await _cafSdk.initializeCafSdk(
  cafSdkConfiguration: config,
  documentDetectorConfiguration: documentDetectorConfig,
  documentDetectorUIConfiguration: documentDetectorUIConfig,
  faceLivenessConfiguration: faceLivenessConfig,
  faceLivenessUIConfiguration: faceLivenessUIConfig,
);
```

### Module-Specific Configuration

#### Face Liveness Configuration

You can configure the Face Liveness module by creating a `CafFaceLivenessConfiguration`. When using the optional PayFace (Fortface) provider, use `payFaceDebugMode` to enable debug mode for that provider.

```dart
final faceLivenessConfig = CafFaceLivenessConfiguration(
  loading: true,                                                  // Displays loading screen during processing
  authBaseUrl: 'https://base-url.com',                            // Optional, endpoint for authentication
  livenessBaseUrl: 'wss://base-url.com',                          // Optional, endpoint for liveness check
  certificates: ['4d69f16113bed7d62ca56feb68d32a0fcb7293d3960='], // Optional, only when using reverse proxy
  screenCaptureEnabled: true,                                     // Allows screen capture if necessary
  debugModeEnabled: true,                                         // Enables debug logging
  executeFaceAuth: false,                                         // Enables face authentication
  maxRetryAttempts: 2,                                            // Maximum retry attempts
  payFaceDebugMode: false,                                        // Optional, enables debug mode for PayFace (Fortface) provider
);
```

#### Document Detector Configuration

You can configure the Document Detector module by creating a `CafDocumentDetectorConfiguration`:

```dart
final documentDetectorConfig = CafDocumentDetectorConfiguration(
  flow: [
    CafDocumentDetectorFlow(document: CafDocument.rgFront),
    CafDocumentDetectorFlow(document: CafDocument.rgBack),
  ],
  securitySettings: CafDocumentDetectorSecuritySettings(
    useAdb: true,
    useDebug: true,
    useDevelopmentMode: true,
  ),
  manualCaptureEnabled: true,
  manualCaptureTime: 30,
  requestTimeout: 60,
  showPopup: true,
  maxRetryAttempts: 2,
  uploadSettings: CafDocumentDetectorUploadSettings(
    enable: true,
    compress: true,
    fileFormats: [CafFileFormat.png, CafFileFormat.jpg],
    maxFileSize: 5, // 5MB
  ),
);
```

***

## Event Handling

{% hint style="warning" %}
Ensure the JWT response is evaluated on the backend. This process must include validating the token's signature and verifying the `isAlive` and `isMatch` fields. Do not perform these validations on the client side.
{% endhint %}

The `eventStream` from the `CafSdk` class provides a **typed** `Stream<CafResponse>` generated during the execution of the capture flow. Each `CafResponse` has exactly one populated field, which indicates the event type:

| Field       | Type                  | Description                                                                             |
| ----------- | --------------------- | --------------------------------------------------------------------------------------- |
| `loading`   | `bool`                | Indicates the start of module processing                                                |
| `loaded`    | `bool`                | Indicates that the module has been processed                                            |
| `success`   | `CafSuccessResponse?` | Upon successful completion; contains `moduleName` and `signedResponse`                  |
| `error`     | `CafErrorResponse?`   | A problem occurred during execution; contains `type` and `description`                  |
| `failure`   | `CafFailureResponse?` | Indicates a Face Liveness failure; contains `type`, `description`, and `response`       |
| `log`       | `CafLog?`             | Log messages with different levels; contains `level` (DEBUG, USAGE, INFO) and `message` |
| `cancelled` | `bool`                | Indicates that the user or system interrupted the flow                                  |

> **Migration note (v2.0.0):** `eventStream` now emits typed `CafResponse` objects instead of raw `Map` payloads. Replace any `event['eventName']` / `event['response']` access with the typed fields shown above.

**Example of event handling:**

```dart
final _cafSdk = CafSdk();
StreamSubscription<CafResponse>? _eventSubscription;

void _initializeEventStream() {
  _eventSubscription = _cafSdk.eventStream.listen((event) {
    if (!mounted) return;

    if (event.loading) {
      print('Loading...');
    } else if (event.loaded) {
      print('Session loaded');
    } else if (event.success != null) {
      print('Success: ${event.success!.moduleName} -> ${event.success!.signedResponse}');
    } else if (event.error != null) {
      print('Error: ${event.error!.type} - ${event.error!.description}');
    } else if (event.failure != null) {
      print('Failure: ${event.failure!.type} - ${event.failure!.description}');
    } else if (event.log != null) {
      print('Log: ${event.log!.level} - ${event.log!.message}');
    } else if (event.cancelled) {
      print('Cancelled by user');
    }
  });
}

@override
void dispose() {
  _eventSubscription?.cancel();
  super.dispose();
}
```

### Error Types (CafErrorType)

| Enum Case                          | Trigger Condition                                  |
| ---------------------------------- | -------------------------------------------------- |
| `CAMERA_PERMISSION`                | Camera access denied                               |
| `UNSUPPORTED_DEVICE`               | Unsupported device specs                           |
| `NETWORK_EXCEPTION`                | Network connectivity issues                        |
| `SERVER_EXCEPTION`                 | Backend processing failure                         |
| `TOKEN_EXCEPTION`                  | Invalid/expired token                              |
| `CAPTURE_ALREADY_ACTIVE_EXCEPTION` | Concurrent capture session                         |
| `UNEXPECTED_ERROR_EXCEPTION`       | Critical unrecoverable error                       |
| `USER_TIMEOUT_EXCEPTION`           | Capture timeout exceeded                           |
| `IMAGE_NOT_FOUND_EXCEPTION`        | Missing image data                                 |
| `TOO_MANY_REQUESTS_EXCEPTION`      | API rate limit exceeded                            |
| `UNKNOWN_EXCEPTION`                | Unclassified error                                 |
| `LIBRARY_EXCEPTION`                | Low-level framework error                          |
| `PERMISSION_EXCEPTION`             | Missing system permissions                         |
| `INVALID_EXCEPTION`                | Invalid response received                          |
| `SEQUENCE_INVALID`                 | Invalid operation sequence                         |
| `LIVENESS_EXCEPTION`               | Face liveness specific error                       |
| `FINGERPRINT_EXCEPTION`            | Fingerprint related error                          |
| `STORAGE_EXCEPTION`                | Storage access error                               |
| `PROXY_EXCEPTION`                  | Proxy configuration error                          |
| `SECURITY_EXCEPTION`               | Security validation error                          |
| `INVALID_RESPONSE_EXCEPTION`       | Invalid response payload received from a module    |
| `CAMERA_EXCEPTION`                 | Camera initialization or runtime failure           |
| `FACE_AUTHENTICATION`              | Error during face authentication (executeFaceAuth) |
| `BRIDGE_EXCEPTION`                 | Native ↔ Flutter bridge communication error        |

### Failure Types (CafFailureType)

|      Enum Case      | Trigger Condition          | GPA |  LA |
| :-----------------: | -------------------------- | :-: | :-: |
|      `UNKNOWN`      | Generic failure            |  ✅  |  ❌  |
| `TOO_MUCH_MOVEMENT` | Excessive head motion      |  ✅  |  ❌  |
|     `TOO_BRIGHT`    | Over-illumination          |  ✅  |  ❌  |
|      `TOO_DARK`     | Low light conditions       |  ✅  |  ❌  |
|  `MISALIGNED_FACE`  | Face alignment failure     |  ✅  |  ❌  |
|    `FACE_TOO_FAR`   | Face too distant           |  ✅  |  ❌  |
|   `FACE_TOO_CLOSE`  | Face too close             |  ✅  |  ❌  |
|     `SUNGLASSES`    | Eye-obscuring eyewear      |  ✅  |  ❌  |
|   `OBSCURED_FACE`   | Partial face obstruction   |  ✅  |  ✅  |
|    `EYES_CLOSED`    | Closed eyes during capture |  ✅  |  ✅  |
|   `MULTIPLE_FACES`  | Multiple faces detected    |  ✅️ |  ✅️ |
|  `BACKGROUND_ISSUE` | Unsuitable background      |  ❌  |  ✅  |
|    `DEVICE_ISSUE`   | Incompatible device        |  ❌  |  ✅  |
|      `EYEWEAR`      | Eyewear detected           |  ❌  |  ✅  |
|   `FACE_NOT_FOUND`  | Face detection failure     |  ❌  |  ✅  |
|   `FRAMES_BLURRY`   | Blurry frames detected     |  ❌  |  ✅  |
|    `MOTION_ISSUE`   | Device motion error        |  ❌  |  ✅  |
|  `LIGHTING_ISSUES`  | Poor lighting conditions   |  ❌  |  ✅  |
|      `REJECTED`     | Transaction rejected       |  ❌  |  ✅  |
|    `SYSTEM_ERROR`   | Internal system error      |  ❌  |  ✅  |
|      `TIMEOUT`      | Session timeout            |  ❌  |  ✅  |
|   `USER_NOT_FOUND`  | User lookup failure        |  ❌  |  ✅  |
|   `DEVICE_RESTART`  | Device state error         |  ❌  |  ✅  |
|  `PROCESSING_FAULT` | Processing error           |  ❌  |  ✅  |

***

## Document Types

### Supported Documents (CafDocument)

| Name         | Description                                                                                                    |
| ------------ | -------------------------------------------------------------------------------------------------------------- |
| `RG_FRONT`   | Front side of the RG document, where the photo is located                                                      |
| `RG_BACK`    | Back side of the RG document                                                                                   |
| `RG_FULL`    | Open RG document, displaying both the front and back sides together                                            |
| `CNH_FRONT`  | Front side of the CNH document, where the photo is located                                                     |
| `CNH_BACK`   | Back side of the CNH document                                                                                  |
| `CNH_FULL`   | Open CNH document, displaying both the front and back sides together                                           |
| `CRLV`       | CRLV document                                                                                                  |
| `RNE_FRONT`  | Front side of the RNE or RNM document                                                                          |
| `RNE_BACK`   | Back side of the RNE or RNM document                                                                           |
| `CTPS_FRONT` | Front side of the CTPS document, where the photo is located                                                    |
| `CTPS_BACK`  | Back side of the CTPS document                                                                                 |
| `PASSPORT`   | Passport document, displaying the photo and personal data                                                      |
| `ANY`        | Allows submission of any type of document, including all those listed above or any other unclassified document |

### Supported File Formats (CafFileFormat)

| Type   | Value             |
| ------ | ----------------- |
| `PNG`  | `image/png`       |
| `JPG`  | `image/jpg`       |
| `JPEG` | `image/jpeg`      |
| `PDF`  | `application/pdf` |
| `HEIF` | `image/heif`      |
| `HEIC` | `image/heic`      |

***

## Advanced Configuration

### Face Liveness UI Configuration

When using the UI module, you can customize instruction screens:

```dart
final faceLivenessUIConfig = CafFaceLivenessUIConfiguration(
  loading: true,
  authBaseUrl: "https://my.proxy.io/v1/faces/", 
  livenessBaseUrl: "wss://my.proxy.io/ws/",    
  certificates: [
    "4d69f16113bed7d62ca56feb68d32a0fcb7293d3960=",
    "50f71c5dda30741ee4be1ac378e12539b0d1d511f99=",
    "9f85e26c1ae41f7ac97adc4099be7f2a40759510ab9=",
  ],
  screenCaptureEnabled: true,
  debugModeEnabled: true,
  executeFaceAuth: false, 
  maxRetryAttempts: 2,
  payFaceDebugMode: false,
  instructionScreen: CafFaceLivenessUIInstructionScreenConfiguration(
    image: "scan_icon", // Image URL or local asset name
    title: "Custom title",
    description: "Follow the steps below:",
    steps: ["Keep the phone steady", "Ensure good lighting"],
    buttonText: "Start scanning",
  ),
);
```

### Document Detector UI Configuration

```dart
final documentDetectorUIConfig = CafDocumentDetectorUIConfiguration(
  flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)], 
  manualCaptureEnabled: true,
  manualCaptureTime: 45,
  requestTimeout: 60,
  showPopup: true,
  securitySettings: CafDocumentDetectorSecuritySettings(
    useDebug: true,
    useDevelopmentMode: true,
    useAdb: true,
  ),
  maxRetryAttempts: 2,
  instructionScreen: CafDocumentDetectorUIInstructionScreenConfiguration(
    enable: true,
    captureTitle: "Capture your document",
    captureSteps: [
      "Keep the phone steady",
      "Ensure good lighting",
      "Avoid reflections"
    ],
    buttonText: "Start",
  ),
  documentSelectionScreen: CafDocumentDetectorUIDocumentSelectionScreenConfiguration(
    title: "Select the document type",
    description: "Choose which document you want to submit",
  ),
);
```

### Proxy Configuration

For Document Detector proxy settings:

```dart
final documentDetectorConfig = CafDocumentDetectorConfiguration(
  flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
  proxySettings: CafDocumentDetectorProxySettings(
    hostname: "proxy.example.com",
    port: 8080,
    authentication: CafDocumentDetectorProxySettingsAuthentication(
      user: "username",
      password: "password"
    ),
  ),
);
```

### Message Customization

Customize messages displayed during the capture flow:

```dart
final documentDetectorConfig = CafDocumentDetectorConfiguration(
  flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
  messageCustomization: CafDocumentDetectorMessageCustomization(
    waitMessage: "Preparing camera...",
    fitTheDocumentMessage: "Position the document within the frame",
    holdItMessage: "Hold steady...",
    verifyingQualityMessage: "Verifying document quality...",
    lowQualityDocumentMessage: "Document quality is too low. Please try again.",
    uploadingImageMessage: "Uploading document...",
    positiveButtonMessage: "Continue",
  ),
);
```

***

## Complete Implementation Example

Here's a complete example showing both Face Liveness UI and Document Detector UI:

```dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:caf_sdk/caf_sdk.dart';
import 'package:caf_sdk/types/index.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CAF SDK Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const CafSdkExamplePage(),
    );
  }
}

class CafSdkExamplePage extends StatefulWidget {
  const CafSdkExamplePage({super.key});

  @override
  State<CafSdkExamplePage> createState() => _CafSdkExamplePageState();
}

class _CafSdkExamplePageState extends State<CafSdkExamplePage> {
  final _cafSdk = CafSdk();
  StreamSubscription<CafResponse>? _eventSubscription;

  final String _mobileToken = "token";
  final String _personId = "personId";
  final CafEnvironment _environment = CafEnvironment.dev;

  @override
  void initState() {
    super.initState();
    _initializeEventStream();
  }

  @override
  void dispose() {
    _eventSubscription?.cancel();
    super.dispose();
  }

  void _initializeEventStream() {
    _eventSubscription = _cafSdk.eventStream.listen((event) {
      if (!mounted) return;

      if (event.loading) {
        print('[CAF SDK EVENT]: loading');
      } else if (event.loaded) {
        print('[CAF SDK EVENT]: loaded');
      } else if (event.success != null) {
        print('[CAF SDK EVENT]: success');
        print('[CAF SDK EVENT]: ${event.success!.moduleName} -> ${event.success!.signedResponse}');
      } else if (event.error != null) {
        print('[CAF SDK EVENT]: error');
        print('[CAF SDK EVENT]: ${event.error!.type} - ${event.error!.description}');
      } else if (event.failure != null) {
        print('[CAF SDK EVENT]: failure');
        print('[CAF SDK EVENT]: ${event.failure!.type} - ${event.failure!.description}');
      } else if (event.log != null) {
        print('[CAF SDK EVENT]: log');
        print('[CAF SDK EVENT]: ${event.log!.level} - ${event.log!.message}');
      } else if (event.cancelled) {
        print('[CAF SDK EVENT]: cancelled');
      }
    });
  }

  Future<void> _initializeCafSdk() async {
    try {
      // SDK Configuration
      final config = CafSdkConfiguration(
        mobileToken: _mobileToken,
        personId: _personId,
        environment: _environment,
        configuration: CafSdkBuilderConfiguration(
          presentationOrder: [
            CafModuleType.faceLivenessUi,
            CafModuleType.documentDetectorUi,
          ],
          enableSecurityModule: true,
          waitForAllServices: true,
        ),
      );

      // Face Liveness UI Configuration
      CafFaceLivenessUIConfiguration?
      faceLivenessUIConfig = CafFaceLivenessUIConfiguration(
        loading: true,
        debugModeEnabled: true,
        payFaceDebugMode: false,
        instructionScreen:
            CafFaceLivenessUIInstructionScreenConfiguration(
              title: "Face Liveness",
              description:
                  "Position your face in the center and follow the instructions",
              steps: [
                "Center your face",
                "Follow the instructions",
                "Stay still",
              ],
              buttonText: "Start",
            ),
      );

      // Document Detector UI Configuration
      CafDocumentDetectorUIConfiguration?
      documentDetectorUIConfig = CafDocumentDetectorUIConfiguration(
        flow: [
          CafDocumentDetectorFlow(document: CafDocument.rgFront),
          CafDocumentDetectorFlow(document: CafDocument.rgBack),
          CafDocumentDetectorFlow(document: CafDocument.rgFull),
          CafDocumentDetectorFlow(document: CafDocument.cnhFront),
          CafDocumentDetectorFlow(document: CafDocument.cnhBack),
          CafDocumentDetectorFlow(document: CafDocument.cnhFull),
          CafDocumentDetectorFlow(document: CafDocument.crlv),
          CafDocumentDetectorFlow(document: CafDocument.rneFront),
          CafDocumentDetectorFlow(document: CafDocument.rneBack),
          CafDocumentDetectorFlow(document: CafDocument.ctpsFront),
          CafDocumentDetectorFlow(document: CafDocument.ctpsBack),
          CafDocumentDetectorFlow(document: CafDocument.passport),
          CafDocumentDetectorFlow(document: CafDocument.any),
        ],
        uploadSettings: CafDocumentDetectorUploadSettings(enable: true),
        manualCaptureEnabled: false,
        manualCaptureTime: 45,
        showPopup: true,
        previewShow: false,
        securitySettings: CafDocumentDetectorSecuritySettings(
          useAdb: true,
          useDebug: true,
          useDevelopmentMode: true,
        ),
        instructionScreen:
            CafDocumentDetectorUIInstructionScreenConfiguration(
              enable: true,
              captureTitle: "Capture Title",
              captureSteps: ["Capture Step 1", "Capture Step 2"],
              uploadTitle: "Upload Title",
              uploadSteps: ["Upload Step 1", "Upload Step 2"],
              buttonText: "Button Text",
            ),
        documentSelectionScreen:
            CafDocumentDetectorUIDocumentSelectionScreenConfiguration(
              title: "Document Selection Title",
              description: "Document Selection Description",
            ),
      );

      await _cafSdk.initializeCafSdk(
        cafSdkConfiguration: config,
        documentDetectorUIConfiguration: documentDetectorUIConfig,
        faceLivenessUIConfiguration: faceLivenessUIConfig,
      );

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('CAF SDK initialized successfully!'),
            backgroundColor: Colors.green,
          ),
        );
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('CAF SDK Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _ConfigurationCard(
              mobileToken: _mobileToken,
              personId: _personId,
              environment: _environment,
            ),
            const SizedBox(height: 16),

            _ActionButtons(onInitialize: _initializeCafSdk),
            const SizedBox(height: 16),
          ],
        ),
      ),
    );
  }
}

class _ConfigurationCard extends StatelessWidget {
  const _ConfigurationCard({
    required this.mobileToken,
    required this.personId,
    required this.environment,
  });

  final String mobileToken;
  final String personId;
  final CafEnvironment environment;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'CAF SDK Configuration',
              style: Theme.of(context).textTheme.titleLarge,
            ),
            const SizedBox(height: 16),
            Text(
              'Mobile Token: ${mobileToken.length > 20 ? '${mobileToken.substring(0, 20)}...' : mobileToken}',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            Text(
              'Person ID: $personId',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            Text(
              'Environment: $environment',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
          ],
        ),
      ),
    );
  }
}

class _ActionButtons extends StatelessWidget {
  const _ActionButtons({
    required this.onInitialize,
  });

  final VoidCallback onInitialize;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: ElevatedButton(
            onPressed: onInitialize,
            style: ElevatedButton.styleFrom(
              padding: const EdgeInsets.symmetric(vertical: 16),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(8),
              ),
            ),
            child: Text('Initialize SDK'),
          ),
        ),
        const SizedBox(width: 8),
      ],
    );
  }
}
```

***

## ProGuard/R8 Rules

Add these ProGuard/R8 rules to your `proguard-rules.pro` file for Android:

```proguard
# Flutter ProGuard/R8 rules for Caf SDK
# These rules ensure the CAF SDK plugin works correctly in release builds

# The Android pre-handler for exceptions is loaded reflectively (via ServiceLoader).
-keep class kotlinx.coroutines.experimental.android.AndroidExceptionPreHandler { *; }

### GSON ##################################################################
# Gson uses generic type information stored in a class file when working with fields.
# ProGuard removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
### END GSON ##################################################################

### Retrofit ##################################################################
# Preserve generic signatures, inner classes, and enclosing methods for Retrofit reflection.
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retain runtime-visible annotations on methods and parameters.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Keep annotation default values.
-keepattributes AnnotationDefault
# Retain service method parameters for interfaces with Retrofit annotations.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}
# Suppress warnings for build tooling and certain JSR 305 annotations.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn javax.annotation.**
-dontwarn kotlin.Unit
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# Explicitly keep Retrofit interfaces to prevent nullification by R8.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
# Preserve continuations used by Kotlin suspend functions.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# For R8 full mode: keep generic return types for Retrofit methods.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
# Preserve Retrofit Response class.
-keep,allowobfuscation,allowshrinking class retrofit2.Response
### END Retrofit ##############################################################

### OkHttp ####################################################################
# Suppress warnings for JSR 305 annotations.
-dontwarn javax.annotation.**
# Adapt resource filenames for internal public suffix database.
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
# Suppress warnings for Animal Sniffer and platform-specific classes.
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
# Keep all OkHttp and Okio classes.
-keep class okhttp3.** { *; }
-dontwarn okhttp3.**
-keep class okio.** { *; }
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
### END OkHttp ################################################################

### Kotlin Serialization ######################################################
# Keep Companion objects for serializable classes.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}
# Keep serializer functions on companion objects.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}
# Retain INSTANCE and serializer for serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}
# Preserve Companion objects in kotlinx.serialization.json.
-keepclassmembers class kotlinx.serialization.json.** {
    *** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
    kotlinx.serialization.KSerializer serializer(...);
}
# Preserve serializer lookup for serializable classes (adjust package name as needed).
-keepclassmembers @kotlinx.serialization.Serializable class packeage.** {
    *** Companion;
    *** INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}
### END Kotlin Serialization #################################################

### AutoValue ################################################################
-dontwarn com.google.auto.**
-dontwarn autovalue.shaded.com.**
-dontwarn sun.misc.Unsafe
-dontwarn javax.lang.model.element.Modifier
### END AutoValue ############################################################

### Flutter Plugin ###########################################################
# Keep Flutter plugin classes
-keep class io.flutter.plugins.** { *; }

# Keep method channel classes
-keep class * extends io.flutter.plugin.common.MethodChannel$MethodCallHandler { *; }
-keep class * extends io.flutter.plugin.common.MethodChannel$Result { *; }

# Keep plugin registrar
-keep class io.flutter.plugins.GeneratedPluginRegistrant { *; }

# Keep CAF SDK Flutter plugin classes
-keep class io.caf.sdk.flutter.** { *; }
### END Flutter Plugin #######################################################

### CAF - Combate a Fraude ######################################################
# Keep exceptions attributes.
-keepattributes Exceptions
# Preserve all classes, interfaces, and class members for CAF modules.
-keep class com.caf.facelivenessiproov.** { *; }
-keep class com.combateafraude.documentdetector.** { *; }
-keep class com.combateafraude.** { *; }
-keep interface com.combateafraude.** { *; }
-keep class io.caf.** { *; }
-keep interface io.caf.** { *; }
-keepclassmembers class com.combateafraude.** { *; }
# Suppress warnings for java.nio.file and certain OkHttp internal classes.
-dontwarn java.nio.file.*
-dontwarn com.squareup.okhttp.internal.Platform
# Keep fields in classes extending GeneratedMessageLite (for Tink usage).
-keepclassmembers class * extends com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite {
  <fields>;
}
# Preserve TensorFlow classes.
-keep class org.tensorflow.** { *; }
-keep class org.tensorflow.**$* { *; }
-dontwarn org.tensorflow.**
# Preserve IProov classes and Protobuf classes.
-keep public class com.iproov.sdk.IProov { public *; }
-keep class com.iproov.** { *; }
-keep class com.iproov.**$* { *; }
-keep class com.google.protobuf.** { *; }
-keep class com.google.protobuf.**$* { *; }
-dontwarn com.google.protobuf.**
# Suppress warnings for concurrent Flow classes.
-dontwarn java.util.concurrent.Flow*
# Preserve Kotlin and kotlinx classes.
-keep class kotlin.** { *; }
-keep class kotlinx.** { *; }
# Preserve all FortFace/PayFace SDK classes to prevent obfuscation issues
-keep class br.com.fortface.** { *; }
-keep interface br.com.fortface.** { *; }
-keepclassmembers class br.com.fortface.** { *; }
# Keep all inner classes and enums
-keepclassmembers class br.com.fortface.**$* { *; }
# Preserve JSON classes completely (critical for PayFace)
-keep class org.json.** { *; }
-keepclassmembers class org.json.** { *; }
# Preserve JSON-related classes used by PayFace SDK
-keepclassmembers class * {
    @org.json.** *;
}
# Suppress warnings for PayFace SDK
-dontwarn br.com.fortface.**
-dontwarn com.android.tools.lint.**
-dontwarn io.caf.sdk.common.jvmshared.lint.**
### END CAF - Combate a Fraude ##################################################
```

***

## Technical Support and Usage Tips

**Technical Support** If you have any questions or difficulties with the integration, contact Caf's technical support.

**Usage Tips**

* **Run tests:** Perform tests on real devices to validate requirements and flow performance
* **Explore customizations:** Use advanced customization options to tailor the flow to your project's needs
* **Monitor performance:** Integrate monitoring tools to track logs and the flow's performance in production
* **Handle errors gracefully:** Implement proper error handling for all possible error and failure scenarios
* **Test with different devices:** Ensure compatibility across various device specifications and screen sizes

***

## Release Notes

### caf\_sdk\@2.0.0

#### Release date

* 07-06-2026

{% hint style="warning" %}
**Breaking change:** The `eventStream` now emits a **typed `Stream<CafResponse>`** instead of a `Stream<dynamic>` with raw `Map` payloads. Update every listener: replace `event['eventName']` / `event['response']` with the typed fields — `event.success`, `event.error`, `event.failure`, `event.log`, `event.loading`, `event.loaded`, and `event.cancelled`. See [Event Handling](#event-handling) for the full migration example.
{% endhint %}

#### Highlights

* **More consistent error reporting**: Errors occurring during flow initialization that relate to the SDK's internal integration are now emitted via the `error` event as `BRIDGE_EXCEPTION`, so they can be handled the same way as any other SDK error.

#### Breaking Changes

* **Typed event stream**: `CafSdk.eventStream` is now `Stream<CafResponse>`. Consumers must access the typed fields of `CafResponse` (`success`, `error`, `failure`, `log`, `loading`, `loaded`, `cancelled`) instead of indexing a `Map`.
* **Flattened module configuration classes**: The per-module `...BuilderConfiguration` wrappers were removed. Fields are now passed directly on the module configuration objects, and the UI configurations extend the base configuration instead of nesting it:
  * `CafFaceLivenessBuilderConfiguration` removed — pass fields directly on `CafFaceLivenessConfiguration`.
  * `CafDocumentDetectorBuilderConfiguration` removed — pass fields directly on `CafDocumentDetectorConfiguration`.
  * `CafFaceLivenessUIBuilderInstructionScreenConfiguration` → `CafFaceLivenessUIInstructionScreenConfiguration`, and the field `instructionScreenConfiguration` → `instructionScreen`.
  * `CafDocumentDetectorUIBuilderInstructionScreenConfiguration` → `CafDocumentDetectorUIInstructionScreenConfiguration`, and the field `instructionScreenConfiguration` → `instructionScreen`.
  * `CafDocumentDetectorUIBuilderDocumentSelectionScreenConfiguration` → `CafDocumentDetectorUIDocumentSelectionScreenConfiguration`, and the field `documentSelectionScreenConfiguration` → `documentSelectionScreen`.
  * The SDK-level `CafSdkConfiguration` is unchanged and still takes `configuration: CafSdkBuilderConfiguration(...)`.
* **`initializeCafSdk` return type**: changed from `Future<bool?>` to `Future<bool>`.

#### Updates

* **Event name constants**: Added the `CafSdkEventName` constants (`CafUnifiedEvent.*`) for identifying emitted events.
* **New `CafErrorType` values**: Added `INVALID_RESPONSE_EXCEPTION`, `CAMERA_EXCEPTION`, `FACE_AUTHENTICATION`, and `BRIDGE_EXCEPTION`. Note that `BRIDGE_EXCEPTION` reports errors that occur while initializing or starting the flow; listen for it on the `error` event and handle it as part of your normal error handling.
* **`CafSuccessResponse`**: `signedResponse` is now typed as `String?` (previously `dynamic`), and `moduleName` resolution is more resilient to native identifier variations.

#### Migration Guide — 1.x → 2.0.0

Three things changed for integrators: how you read events, how you build module configurations, and the return type of `initializeCafSdk`. The SDK-level `CafSdkConfiguration` (with `CafSdkBuilderConfiguration`) is unchanged.

**1. Read events from the typed stream**

```dart
// Before (1.x) — raw Map
_cafSdk.eventStream.listen((event) {
  final name = event['eventName'];
  final response = event['response'];
});

// After (2.0.0) — typed CafResponse
_cafSdk.eventStream.listen((event) {
  if (event.success != null) {
    print('${event.success!.moduleName} -> ${event.success!.signedResponse}');
  } else if (event.error != null) {
    print('${event.error!.type} - ${event.error!.description}');
  }
  // also: event.failure, event.log, event.loading, event.loaded, event.cancelled
});
```

**2. Remove the module `...BuilderConfiguration` wrapper**

Pass the fields directly on the module configuration object.

```dart
// Before (1.x)
final faceLivenessConfig = CafFaceLivenessConfiguration(
  configuration: CafFaceLivenessBuilderConfiguration(
    loading: true,
    maxRetryAttempts: 2,
  ),
);

// After (2.0.0)
final faceLivenessConfig = CafFaceLivenessConfiguration(
  loading: true,
  maxRetryAttempts: 2,
);
```

```dart
// Before (1.x)
final documentDetectorConfig = CafDocumentDetectorConfiguration(
  configuration: CafDocumentDetectorBuilderConfiguration(
    flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
    manualCaptureEnabled: false,
  ),
);

// After (2.0.0)
final documentDetectorConfig = CafDocumentDetectorConfiguration(
  flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
  manualCaptureEnabled: false,
);
```

**3. Update the UI configurations (wrapper + renamed types and fields)**

```dart
// Before (1.x)
final faceLivenessUIConfig = CafFaceLivenessUIConfiguration(
  configuration: CafFaceLivenessBuilderConfiguration(loading: true),
  instructionScreenConfiguration:
      CafFaceLivenessUIBuilderInstructionScreenConfiguration(title: 'Face Liveness'),
);

// After (2.0.0)
final faceLivenessUIConfig = CafFaceLivenessUIConfiguration(
  loading: true,
  instructionScreen:
      CafFaceLivenessUIInstructionScreenConfiguration(title: 'Face Liveness'),
);
```

```dart
// Before (1.x)
final documentDetectorUIConfig = CafDocumentDetectorUIConfiguration(
  configuration: CafDocumentDetectorBuilderConfiguration(
    flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
  ),
  instructionScreenConfiguration:
      CafDocumentDetectorUIBuilderInstructionScreenConfiguration(enable: true),
  documentSelectionScreenConfiguration:
      CafDocumentDetectorUIBuilderDocumentSelectionScreenConfiguration(title: 'Choose document'),
);

// After (2.0.0)
final documentDetectorUIConfig = CafDocumentDetectorUIConfiguration(
  flow: [CafDocumentDetectorFlow(document: CafDocument.rgFront)],
  instructionScreen:
      CafDocumentDetectorUIInstructionScreenConfiguration(enable: true),
  documentSelectionScreen:
      CafDocumentDetectorUIDocumentSelectionScreenConfiguration(title: 'Choose document'),
);
```

**4. Rename type imports (if you imported the removed types)**

| Removed (1.x)                                                      | Use instead (2.0.0)                                         |
| ------------------------------------------------------------------ | ----------------------------------------------------------- |
| `CafFaceLivenessBuilderConfiguration`                              | `CafFaceLivenessConfiguration`                              |
| `CafDocumentDetectorBuilderConfiguration`                          | `CafDocumentDetectorConfiguration`                          |
| `CafFaceLivenessUIBuilderInstructionScreenConfiguration`           | `CafFaceLivenessUIInstructionScreenConfiguration`           |
| `CafDocumentDetectorUIBuilderInstructionScreenConfiguration`       | `CafDocumentDetectorUIInstructionScreenConfiguration`       |
| `CafDocumentDetectorUIBuilderDocumentSelectionScreenConfiguration` | `CafDocumentDetectorUIDocumentSelectionScreenConfiguration` |

**5. Update the `initializeCafSdk` return type**

`initializeCafSdk` now returns `Future<bool>` instead of `Future<bool?>`. Remove any null checks on the awaited result.

```dart
// Before (1.x)
final bool? started = await _cafSdk.initializeCafSdk(
  cafSdkConfiguration: config,
);
if (started == true) {
  // ...
}

// After (2.0.0)
final bool started = await _cafSdk.initializeCafSdk(
  cafSdkConfiguration: config,
);
if (started) {
  // ...
}
```

### caf\_sdk\@1.5.0

#### Release date

* 05-25-2026

#### Updates

* **Payface Liveness Provider (Android)**: Update version from `1.18.2` to `1.19.2`.
* **Payface Liveness Provider (iOS)**: Update version from `1.5.2` to `1.8.2`.

#### Fixes

**FaceLiveness**

* Infinite loading error occurs when the SDK returns an error.
* First initialization not working when using `Payface` provider.

### caf\_sdk\@1.4.0

#### Release date

* 05-08-2026

#### Fixes

* **DocumentDetector**: Fixed behavior when handling RG (Brazilian National Identity Card) with the digital document option.

### caf\_sdk\@1.3.0

#### Release date

* 04-13-2026

{% hint style="warning" %}
**Breaking change :** Face Liveness providers can now be configured in `caf-modules-config.json` via **`livenessProviders`** (string or array). When provided, it must list the chosen provider(s). Do not use **`iproov-lite`** and **`iproov-full`** together—**`iproov-full`** uses a different version of Protobuf, and combining them will cause duplicate class errors at build time. **PayFace** requires **`iproov-lite`** (Protobuf JavaLite); pairing PayFace with **`iproov-full`** causes build-time Protobuf conflicts. If omitted, the SDK defaults to **`iproov-lite`** on both platforms. An **empty or invalid value** causes a build error on **Android**; on **iOS**, an empty value also falls back to `iproov-lite`, but an invalid value causes a build failure. See [Step 2: Configure Module Selection](#step-2-configure-module-selection) for details.
{% endhint %}

#### Highlights

* **Configurable Face Liveness providers**: Choose `iproov-lite`, `iproov-full`, `payface`, and/or `facetec` from `caf-modules-config.json` instead of relying on implicit native defaults.

#### Updates

* **Liveness provider configuration**:
  * New **`livenessProviders`** field in `caf-modules-config.json` for Android and iOS.
  * Documented **Protobuf JavaLite** vs **Protobuf Java** mapping for **`iproov-lite`** vs **`iproov-full`**.
  * Clarified **multi-provider** setups using an array, and the **PayFace + iProov Lite** requirement.
* **iProov Liveness Provider**: Documentation and defaults updated to reflect the new provider selection model.
* **Android ProGuard / R8**: If R8 reports missing classes for lint stubs shipped with the SDK, add the following to `proguard-rules.pro` (also listed under [ProGuard/R8 Rules](#proguardr8-rules)):

```proguard
-dontwarn com.android.tools.lint.**
-dontwarn io.caf.sdk.common.jvmshared.lint.**
```

### caf\_sdk\@1.2.0

#### Release date

* 02-09-2026

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

#### Highlights

* **Updated Liveness Provider**: Critical update to the iProov provider version for improved stability

#### Updates

* **iProov Liveness Provider**: Updated the internal iProov provider version.

### caf\_sdk\@1.1.0

#### Release date

* 02-09-2026

#### Highlights

* **New Security Module**: Introduction of `CafSecurity` module for security validations
* **PayFace Integration**: Added support for PayFace (Fortface) as an optional Face Liveness provider
* **Stability Improvements**: Major crash fixes and stability improvements for the Document Detector module

#### Features

* **CafSecurity Module**:
  * Added a new module specifically for security validations
  * **Configuration**: Added `enableSecurityModule` flag in `CafSdkConfiguration` (default value: `true`)
* **PayFace (Fortface) Integration**:
  * Optional Face Liveness provider integration
  * **Configuration**: New property `payFaceDebugMode` in `CafFaceLivenessConfiguration` to enable debug mode for the PayFace provider

#### Fixes

* **DocumentDetector**:
  * **Activity Lifecycle**: Resolved multiple crashes related to activity lifecycle management (initialization, pause, and resume states)
  * **Camera Lifecycle**: Improved camera resource management and thread lifecycle to prevent crashes during SDK shutdown
  * **UI Components**: Resolved theme compatibility issues and fragment transaction exceptions
  * **Network Requests**: Corrected response body handling to prevent errors when reading network responses
  * **Data Access**: Improved cursor initialization and validation before accessing database data
  * **ANR Prevention**: Optimized document controller instance checks to prevent "Application Not Responding" issues
  * **General**: Internal improvements and stability corrections
* **FaceLiveness**:
  * **Sessions**: Fixed session creation errors
  * **UI**: Fixed color tint on remote images in the Instructions screen

#### Updates

* **Build Configuration**:
  * **ProGuard Rules**: Added necessary ProGuard rules for PayFace integration

### caf\_sdk\@1.0.1

#### Release date

* 03-09-2026

#### Updates

* **Updated iProov Liveness Provider**: Update iProov provider version.
* **Updated iOS minimum deployment target**: Updated to `15.0`.

#### Fixes

* **DocumentDetector**
  * **Fixed crashes in Document Detector module**: Resolved multiple crashes related to activity lifecycle management, including initialization, pause, and resume states.
  * **Fixed crashes related to camera lifecycle**: Improved camera resource management and thread lifecycle to prevent crashes during SDK shutdown and state transitions.
  * **Fixed crashes in UI components**: Resolved theme compatibility issues and fragment transaction exceptions to ensure proper UI behavior.
  * **Fixed crashes in network requests**: Corrected response body handling to prevent errors when reading network responses.
  * **Fixed crashes in data access**: Improved cursor initialization and validation before accessing database data.
  * **Fixed ANR in Document Controller**: Optimized document controller instance checks to prevent application not responding issues.
  * **Internal improvements and corrections**: Additional stability enhancements and bug fixes.

### caf\_sdk\@1.0.0

#### Release date

* 10-27-2025

#### Highlights

* **First Flutter SDK Release**: Complete Flutter implementation of the CAF SDK for identity verification
* **Unified SDK**: Single package containing all CAF modules (Face Liveness and Document Detector) with both core and UI variants
* **Flutter-Native Integration**: Seamless integration with Flutter's widget system and state management
* **Cross-Platform Support**: Full support for both Android and iOS platforms
* **Type-Safe Configuration**: Strongly typed Dart configuration classes for better development experience

#### Features

* **Module Configuration System**:
  * **`caf-modules-config.json`**: Configuration file in project root to specify which modules to include
  * Available modules:
    * `documentDetector`: Enable/disable Document Detector module
    * `faceLiveness`: Enable/disable Face Liveness module
    * `documentDetectorUI`: Enable/disable Document Detector UI module
    * `faceLivenessUI`: Enable/disable Face Liveness UI module
  * Example configuration:

    ```json
    {
      "documentDetector": true,
      "faceLiveness": true,
      "documentDetectorUI": false,
      "faceLivenessUI": false
    }
    ```
* **Core SDK Features**:
  * **CafSdk Class**: Main SDK class for initialization and configuration
  * **Event Stream**: Real-time event handling through Dart streams
  * **Module Management**: Sequential execution of modules with configurable presentation order
  * **Error Handling**: Comprehensive error types and failure handling
  * **Configuration Builder**: Type-safe configuration using builder pattern
* **Face Liveness Module**:
  * **Core Module**: `CafFaceLivenessConfiguration` for programmatic control
  * **UI Module**: `CafFaceLivenessUIConfiguration` with customizable instruction screens
  * **Features**: Authentication URLs, certificate pinning, debug mode, retry attempts
  * **Customization**: Instruction screens with images, titles, descriptions, and steps
* **Document Detector Module**:
  * **Core Module**: `CafDocumentDetectorConfiguration` for programmatic control
  * **UI Module**: `CafDocumentDetectorUIConfiguration` with full UI customization
  * **Document Types**: Support for RG, CNH, Passport, RNE, CTPS, and more
  * **Upload Support**: File upload with compression, format control, and size limits
  * **Proxy Configuration**: Support for proxy servers with authentication
  * **Message Customization**: Customizable user messages throughout the flow
* **Advanced Configuration**:
  * **Color Theming**: Complete UI color customization through `CafColorConfiguration`
  * **Security Settings**: Development flags, debug mode, and security controls
  * **Flow Control**: Manual capture, timeouts, retry attempts, and popup controls
  * **Instruction Screens**: Customizable instruction screens for both modules

#### Technical Implementation

* **Flutter Integration**:
  * **Method Channels**: Native communication through Flutter's method channel system
  * **Stream-Based Events**: Real-time event handling using Dart streams
  * **State Management**: Proper lifecycle management with `StatefulWidget` support
  * **Error Handling**: Comprehensive error handling with typed exceptions
* **Platform Support**:
  * **Android**: Full support with ProGuard/R8 rules and Maven repository configuration
  * **iOS**: Complete integration with CocoaPods and native iOS modules
  * **Permissions**: Proper permission handling for camera and network access
* **Performance**:
  * **Selective Module Loading**: Only load enabled modules to optimize bundle size
  * **Memory Management**: Proper resource cleanup and memory management
  * **Network Optimization**: Efficient network communication with retry mechanisms

#### Installation and Setup

* **Package Installation**: Simple installation via `flutter pub add caf_sdk`
* **Module Configuration**: Easy module selection through JSON configuration file
* **Platform Setup**: Clear instructions for Android and iOS platform configuration
* **Permission Management**: Comprehensive permission setup for both platforms

#### Documentation

* **Complete Examples**: Full implementation examples for both basic and advanced usage
* **Configuration Guide**: Detailed configuration options for all modules
* **Event Handling**: Comprehensive event handling examples and patterns
* **Error Reference**: Complete error types and failure scenarios documentation

#### Breaking Changes

* **First Release**: This is the first release of the Flutter SDK, so there are no breaking changes from previous versions.

#### Known Issues

* **iOS Simulator**: Some features may not work properly in iOS Simulator due to camera limitations
* **Android Emulator**: Camera-dependent features require physical devices for testing
* **Network Requirements**: All modules require internet connectivity for proper operation


---

# 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/flutter/getting-started-with-the-sdk.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.
