> For the complete documentation index, see [llms.txt](https://docs.complycube.com/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.complycube.com/documentation/sdks/sdks-es/integraciones-moviles/sdk-de-flutter/integracion-basada-en-comprobaciones.md).

# Integración basada en comprobaciones

## Descripción general

Esta guía le muestra cómo integrar el **SDK de Flutter** con ComplyCube utilizando el enfoque basado en comprobaciones, dándote control directo sobre cada paso de verificación individual.

<figure><img src="/files/e1abf1b76dcc47e6db4aef4727269eabf2653e30" alt=""><figcaption><p>Vista del SDK móvil</p></figcaption></figure>

{% hint style="warning" %}
Estás viendo la **basado en comprobaciones** guía del SDK: un enfoque que ofrece un control detallado, pero es más adecuado para **socios** o **casos de uso avanzados.**  Recomendamos usar **integración del flujo de trabajo** para la mayoría de las implementaciones.
{% endhint %}

## Flujo de integración

El SDK móvil se ejecuta en tu aplicación móvil, pero depende de tu backend para crear **tokens seguros**. Así es como funciona:

{% stepper %}
{% step %}

#### **Crear un cliente**

Registrar un nuevo **cliente** (es decir, cliente) usando la API de ComplyCube.
{% endstep %}

{% step %}

#### **Generar un token del SDK**

Tu backend solicita un **token JWT** vinculado a ese cliente.
{% endstep %}

{% step %}

#### Inicializa el SDK en tu aplicación móvil

Pasa el token y la configuración al inicializador del SDK.
{% endstep %}

{% step %}

#### Captura documentos, vídeos y selfies

El SDK guía a tu cliente a través de los pasos requeridos.
{% endstep %}

{% step %}

#### Realizar comprobaciones

Los datos capturados se envían de forma segura a ComplyCube para las comprobaciones de verificación, y los resultados se entregan en tiempo real a través de la API o de webhooks.
{% endstep %}
{% endstepper %}

<figure><img src="/files/774a5bf3535ac0a2f47d3d2420252ea3d6bcd43d" alt=""><figcaption><p>Flujo de integración del SDK móvil</p></figcaption></figure>

## Guía de integración

Explore el código fuente y los proyectos de ejemplo en nuestro repositorio: [![GitHub](https://img.shields.io/badge/View%20on-GitHub-black?logo=github)](https://github.com/complycube/complycube-flutter-sdk).<br>

{% stepper %}
{% step %}

#### Instale el SDK

{% tabs %}
{% tab title="Flutter" %}

1. Instala el **ComplyCube Flutter** instalando ejecutando:

   ```bash
   flutter pub add complycube
   ```
2. **iOS**
   1. Completa los **pasos 1 y 2** en la **iOS** pestañas.
   2. Añade el fragmento de código siguiente a tu `ios/PodFile` y ejecuta el `pod install` comando.<br>

      ````ruby
      source 'https://github.com/CocoaPods/Specs.git'

      platform :iOS, '13.0'

      target 'Runner' do
        use_frameworks!
        use_modular_headers!
          ...
          ...
      end
      ...
      post_install do |installer|
       installer.pods_project.targets.each do |target|
         flutter_additional_ios_build_settings(target)
         target.build_configurations.each do |config|
           config.build_settings['ENABLE_BITCODE'] = 'NO'
           config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
           config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
           config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
         end
       end
      end```
      ````
   3. Completa **pasos de permisos de la aplicación** en la **iOS** pestañas.<br>
3. **Android**
   1. Completa los pasos en las **Android** pestaña.

{% hint style="danger" %}

#### objetivo de implementación de iOS

Si estás apuntando a una versión específica de iOS superior a 13.0 para cualquiera de tus dependencias y te encuentras con el siguiente error:<br>

{% code overflow="wrap" %}

```
Compilando para iOS 13.0, pero el módulo 'CocoaLumberjack' tiene un objetivo mínimo de implementación de iOS 15.0
```

{% endcode %}

\
Puedes usar el fragmento de código siguiente en tu PodFile `post_install` script.

```ruby
post_install do |installer|
  ios_13_pods = [
    'Sentry',
    'Analytics',
    'Alamofire',
    'SwiftyJSON',
    'JWTDecode',
    'GooglePlaces',
    'lottie-ios'
  ]
  
  installer.pods_project.targets.each do |target|
      ....
      
      # Establece el objetivo de implementación según el nombre del pod
      if ios_13_pods.any? { |pod_name| target.name.start_with?(pod_name) }
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
        puts "Estableciendo #{target.name} en iOS 13.0"
      else
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
      end
      
      ....
```

{% endhint %}
{% endtab %}

{% tab title="iOS" %}

1. Antes de usar el SDK de ComplyCube, instale el **CocoaPods** plugin ejecutando el siguiente comando en tu terminal:<br>

   ```bash
   sudo gem install cocoapods
   ```

2. Añade repositorios de plugins e instala el pod usando tu `Podfile`:<br>

   ```ruby
   source 'https://github.com/CocoaPods/Specs.git'
   …
   platform :iOS, ’13.0’

   target ‘YourApp’ do
       …
     pod 'ComplyCubeMobileSDK'
   end

   post_install do |installer|
       installer.pods_project.targets.each do |target|
           target.build_configurations.each do |build_configuration|
               build_configuration.build_settings['ENABLE_BITCODE'] = 'NO'
               build_configuration.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
               build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.1'
               build_configuration.build_settings['ARCHS'] = ['$(ARCHS_STANDARD)', 'x86_64']
               build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = ['arm64', 'arm64e', 'armv7', 'armv7s']
               build_configuration.build_settings['GENERATE_INFOPLIST_FILE'] = 'YES'
           end
       end
   end
   ```

\
**Permisos de la aplicación**

Nuestro SDK utiliza la cámara y el micrófono del dispositivo para la captura. Debe añadir las siguientes claves a su aplicación `Info.plist` archivo.

1. `NSCameraUsageDescription`

```xml
<key>NSCameraUsageDescription</key>
<string>Se utiliza para capturar biometría facial y documentos</string>
```

2. `NSMicrophoneUsageDescription`

```xml
<key>NSMicrophoneUsageDescription</key>
<string>Se utiliza para capturar biometría de vídeo</string>
```

{% endtab %}

{% tab title="Android" %}
Nuestro SDK requiere los repositorios siguientes.

```java
repositories {
  mavenCentral()
}

dependencies {
    implementation "com.complycube:complycube-sdk:+"
}
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

#### **Crear un cliente**

Todo flujo de verificación comienza con un **cliente** (es decir, cliente). Usa la API para [crear el cliente](/documentation/api-reference/core-resources/clients/create-a-client.md).

Esto debe hacerse en tu **backend de la app móvil** servidor, no en la propia aplicación móvil.

**Ejemplo de solicitud**

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.complycube.com/v1/clients \
     -H 'Authorization: <YOUR_API_KEY>' \
     -H 'Content-Type: application/json' \
     -d '{
          "type": "person",
          "email": "john.doe@example.com",
          "personDetails":{
               "firstName": "John",
               "lastName" :"Doe"
          }
        }'
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { ComplyCube } = require("@complycube/api");

const complycube = new ComplyCube({ apiKey: "<YOUR_API_KEY>" });

const client = await complycube.client.create({
  type: "person",
  email: "john.doe@example.com",
  personDetails: {
    firstName: "John",
    lastName: "Doe"
  }
});
```

{% endtab %}

{% tab title="Python" %}

```python
from complycube import ComplyCubeClient
cc_api = ComplyCubeClient(api_key='<YOUR_API_KEY>')

new_client = {
    'type':'person',
    'email':'john.doe@example.com',
    'personDetails': {
        'firstName':'John',
        'lastName':'Doe'
    }
}

client = cc_api.clients.create(**new_client)
```

{% endtab %}

{% tab title="PHP" %}

```php
use ComplyCube\ComplyCubeClient;

$ccapi = new ComplyCubeClient('<YOUR_API_KEY>');

$result = $ccapi->clients()->create([
    'type' => 'person',
    'email' => 'john@doe.com',
    'personDetails' => [
        'firstName' => 'John',
        'lastName' => 'Doe'
    ]
]);
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using ComplyCube.Net;
using ComplyCube.Net.Resources.Clients;

var clientApi = new ClientApi(new ComplyCubeClient("<YOUR_API_KEY>"));
var newClient = new ClientRequest {
  type = "person",
  email = "john@doe.com",
  personDetails = new PersonDetails {
    firstName = "John",
    lastName = "Doe"
  }
}

var client = await clientApi.CreateAsync(newClient);
```

{% endtab %}
{% endtabs %}

**Ejemplo de respuesta**

La respuesta contendrá un `id` (el ID del cliente). Es necesario para el siguiente paso.

```json
{
    "id": "5eb04fcd0f3e360008035eb1",
    "type": "person",
    "email": "john.doe@example.com",
    "personDetails": {
        "firstName": "John",
        "apellido": "Doe"
    },
    "createdAt": "2020-01-04T17:24:29.146Z",
    "updatedAt": "2020-01-04T17:24:29.146Z"
}
```

{% hint style="info" %}
Consulta [Referencia de la API de clientes](/documentation/api-reference/core-resources/clients.md) para obtener más información.
{% endhint %}
{% endstep %}

{% step %}

#### Genera un token del SDK

Tu backend debe crear un **token del SDK** para cada nuevo flujo. Este token permite a los clientes enviar datos personales de forma segura desde tu app móvil a ComplyCube.

Los tokens tienen una vida útil corta y no deben reutilizarse.

**Ejemplo de solicitud**

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.complycube.com/v1/tokens \\
     -H 'Authorization: <YOUR_API_KEY>' \
     -H 'Content-Type: application/json' \
     -d '{
           "clientId":"CLIENT_ID",
           "appId": "com.complycube.SampleApp"
         }'
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { ComplyCube } = require("@complycube/api");

const complycube = new ComplyCube({ apiKey: "<YOUR_API_KEY>" });

const token = await complycube.token.generate("CLIENT_ID", {
    appId: "com.complycube.SampleApp"
});
```

{% endtab %}

{% tab title="Python" %}

```python
from complycube import ComplyCubeClient

cc_api = ComplyCubeClient(api_key='<YOUR_API_KEY>')

token = cc_api.tokens.create('CLIENT_ID', appId='com.complycube.SampleApp')
```

{% endtab %}

{% tab title="PHP" %}

```php
use ComplyCube\ComplyCubeClient;

$ccapi = new ComplyCubeClient('<YOUR_API_KEY>');

$token = $ccapi->tokens()->generate('CLIENT_ID', 'com.complycube.SampleApp');
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using ComplyCube.Net;
using ComplyCube.Net.Resources.SDKTokens;

var sdkTokenApi = new SDKTokenApi(new ComplyCubeClient("<YOUR_API_KEY>"));

var sdkTokenRequest = {
  clientId = "CLIENT_ID",
  appId = "com.complycube.SampleApp"
}

var sdkToken = await sdkTokenApi.GenerateToken(sdkTokenRequest);
```

{% endtab %}
{% endtabs %}

**Ejemplo de respuesta**

```json
{
    "token": "<CLIENT_TOKEN>"
}
```

{% hint style="info" %}
Consulta [Referencia de la API de tokens del SDK](/documentation/api-reference/other-resources/tokens.md) para obtener más información.
{% endhint %}
{% endstep %}

{% step %}

#### Prepara las etapas

Configura las etapas que deseas incluir en tu flujo.

```dart
final stages = [
  {
    "name": 'intro',
    "heading": 'Verificación de identidad de Green Bank',
  },
  {
    "name": 'documentCapture',
    "showGuidance": false,
    "useMLAssistance": true,
    "retryLimit": 1,
    "documentTypes": {
      "passport": true,
      "driving_license": ['GB', 'FR'],
    },
  },
  'faceCapture',
];
```

{% endstep %}

{% step %}

#### Inicialice el SDK

Ahora puedes inicializar un flujo. La secuencia de etapas que especifiques determina el orden en que tu cliente ve esas etapas.

```dart
import 'package:complycube_flutter/ComplyCubeMobileSDK.dart';
// ...

final settings = {
  "clientID": "<CLIENT_ID>",
  "clientToken": "<CLIENT_TOKEN>",
  "stages": stages,
  // ...
}


return MaterialApp(
  home: Scaffold(
    appBar: AppBar(
      title: const Text('Integración de ComplyCube'),
    ),
    body: Center(
      child: ElevatedButton(
        onPressed: () => ComplyCube.start(settings),
        child: const Text('Iniciar verificación'),
      ),
    ),
  ),
);
```

{% endstep %}

{% step %}

#### Realizar checks

Usando los resultados devueltos en la `onSuccess` callback, puedes activar tu **backend móvil** para ejecutar las comprobaciones necesarias en tu cliente.

Por ejemplo, usa el resultado de una captura de selfie y documento de la siguiente manera:

* `result.documentId` para ejecutar un [Comprobación de documento](https://docs.complycube.com/api-reference/check-types/document-check).
* `result.documentId` y `result.livePhotoId` para ejecutar un [Comprobación de identidad](https://docs.complycube.com/api-reference/check-types/identity-check).

**Ejemplo de solicitud para una comprobación de documento**

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.complycube.com/v1/checks \
     -H 'Authorization: <YOUR_API_KEY>' \
     -H 'Content-Type: application/json' \
     -d '{
            "clientId":"CLIENT_ID",
            "type": "document_check",
            "documentId":"DOCUMENT_ID"
         }'
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { ComplyCube } = require("@complycube/api");

const complycube = new ComplyCube({ apiKey: "<YOUR_API_KEY>" });

const check = await complycube.check.create("CLIENT_ID", {
    type: "document_check",
    documentId: "DOCUMENT_ID"
});
```

{% endtab %}

{% tab title="Python" %}

```python
from complycube import ComplyCubeClient

cc_api = ComplyCubeClient(api_key='<YOUR_API_KEY>')

check = cc_api.checks.create(
    "CLIENT_ID", 
    "document_check", 
    documentId="DOCUMENT_ID"
)
```

{% endtab %}

{% tab title="PHP" %}

```php
use ComplyCube\ComplyCubeClient;

$ccapi = new ComplyCubeClient('<YOUR_API_KEY>');

$result = $ccapi->checks()->create('CLIENT_ID', [
    'type' => 'document_check',
    'documentId' => 'DOCUMENT_ID'
]);
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using ComplyCube.Net;
using ComplyCube.Net.Resources.Checks;

var checkApi = new CheckApi(new ComplyCubeClient("<YOUR_API_KEY>"));

var checkRequest = new CheckRequest {
  clientId = "CLIENT_ID",
  type = "document_check",
  documentId = "DOCUMENT_ID"
};

var check = await checkApi.CreateAsync(checkRequest);
```

{% endtab %}
{% endtabs %}

Si has configurado webhooks como se describe en nuestra [guía de webhooks](https://docs.complycube.com/documentation/guides/webhooks), se te notificará una vez que un check se complete.

Para recuperar los resultados del check, puedes realizar una solicitud GET de [check](https://docs.complycube.com/api-reference/checks/get-a-check).
{% endstep %}

{% step %}

#### Recuperar los resultados de la verificación

Tu backend móvil puede recuperar todos los resultados de las comprobaciones usando nuestra API.

Todas nuestras comprobaciones son **asíncronas.** Si has [configurado webhooks](https://docs.complycube.com/api-reference/other-resources/webhooks/create-a-webhook) como se describe en nuestra [guía de webhooks](https://docs.complycube.com/documentation/guides/webhooks), se te notificará una vez que un check se complete.

Para recuperar los resultados del check, puedes realizar una solicitud GET de [check](https://docs.complycube.com/api-reference/checks/get-a-check).

**Ejemplo de solicitud**

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X GET https://api.complycube.com/v1/checks/{:checkId} \\
     -H 'Authorization: <YOUR_API_KEY>' 
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { ComplyCube } = require("@complycube/api");

const complycube = new ComplyCube({ apiKey: "<YOUR_API_KEY>" });

const check = await complycube.check.get("CHECK_ID");
```

{% endtab %}

{% tab title="Python" %}

```python
from complycube import ComplyCubeClient

cc_api = ComplyCubeClient(api_key='<YOUR_API_KEY>')

check = cc_api.checks.get('CHECK_ID')
```

{% endtab %}

{% tab title="PHP" %}

```php
use ComplyCube\ComplyCubeClient;

$ccapi = new ComplyCubeClient('<YOUR_API_KEY>');

$check = $ccapi->checks()->get('CHECK_ID');
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using ComplyCube.Net;
using ComplyCube.Net.Resources.Checks;

var checkApi = new CheckApi(new ComplyCubeClient("<YOUR_API_KEY>"));

var check = await checkApi.GetAsync("CHECK_ID");
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

## Etapas

Cada etapa del flujo puede personalizarse para crear el recorrido ideal para tus clientes.

El fragmento a continuación muestra cómo configurar un flujo personalizado utilizando el SDK móvil de ComplyCube.

```dart
final stages = [
  {
    name: 'intro',
    // ... otros ajustes
  },
  {
    name: "consent",
    // ... otros ajustes
  },
  {
    name: 'documentCapture',
    // ... otros ajustes
  },
  {
    name: "faceCapture",
    // ... otros ajustes
  },
  {
    name: "poaCapture",
    // ... otros ajustes
  },
  {
    name: "complete",
    // ... otros ajustes
  }
];

final settings = {
  "clientID": "<CLIENT_ID>",
  "clientToken": "<CLIENT_TOKEN>",
  "stages": stages,
  "language": "en",
  "lookAndFeel": {/*...*/}
}

return MaterialApp(
  home: Scaffold(
    appBar: AppBar(
      title: Text('Integración con ComplyCube'),
    ),
    body: ComplyCubeWidget(settings: settings),
  ),
);
```

### **Bienvenido**

La pantalla de bienvenida siempre se muestra primero en el flujo de verificación. Muestra un mensaje de bienvenida junto con un resumen de las etapas configuradas que el usuario completará.

Puedes personalizar el título de la pantalla para que se alinee con el tono y la identidad de tu aplicación.

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "intro",
      "heading": "Título de pantalla personalizado",
      "message": "Mensaje de bienvenida personalizado.",
    },
    // ... otras etapas
  ],
};
```

### **Consentimiento**

Esta etapa se utiliza para recopilar el consentimiento explícito del usuario antes de continuar con el flujo de verificación. Le ayuda a cumplir con los requisitos regulatorios y de conformidad cuando corresponda.

Puede personalizar el título y el mensaje de la pantalla para que se adapten a sus necesidades legales o de marca.

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "consent",
      "heading": "Título personalizado de la pantalla de consentimiento"
    },
    // ... otras etapas
  ],
};
```

### **Selfie en foto y video**

Puede solicitar una foto selfie  (es decir, una [Foto en vivo](/documentation/api-reference/core-resources/live-photos.md)) o un video selfie (es decir, un [Video en vivo](/documentation/api-reference/core-resources/live-videos.md)) del cliente como parte del proceso de verificación biométrica.

* **Foto**: Captura una imagen estática y realiza una comprobación pasiva de vitalidad antes de permitir el envío.
* **Video**: Graba un video corto en el que el usuario completa un reto en pantalla (p. ej., movimiento de la cabeza o una frase hablada).

{% hint style="warning" %}
Si intenta añadir ambos tipos de etapas, el SDK lanzará un **`ComplyCubeErrorCode.BiometricStageCount`** error que indica que hay varias etapas en conflicto.
{% endhint %}

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "faceCapture",
      "mode": "photo",
      // Habilita la asistencia de ML durante la captura
      "useMLAssistance": false,
    },
    // ... otras etapas
  ],
};
```

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "faceCapture",
      "mode": "video",
      // Habilita la asistencia de ML durante la captura
      "useMLAssistance": false,
    },
    // ... otras etapas
  ],
};
```

### **Documento**

La fase de Documento permite a los usuarios seleccionar y capturar un documento de identidad para su verificación (p. ej., pasaporte, documento de identidad, permiso de residencia). Puede personalizar estas pantallas para:

* Limitar el alcance de los tipos de documento que el cliente puede seleccionar, por ejemplo, solo Pasaporte.
* Configurar los países emisores de documentos permitidos para cada tipo de documento.
* Añadir o quitar la captura automatizada mediante asistencia inteligente.
* Mostrar u ocultar las pantallas de instrucciones antes de la captura.
* Establecer un límite de reintentos para permitir que los clientes avancen en el recorrido independientemente de la calidad de la captura.

{% hint style="info" %}
Si proporciona solo un tipo de documento, se omitirá la pantalla de selección del tipo de documento. La pantalla de selección de país se omitirá si proporciona un único país para un tipo de documento determinado.
{% endhint %}

Puede controlar si las pantallas de instrucciones se muestran antes de cada captura con cámara habilitando o deshabilitando el modo de guía. Deshabilite la guía solo si sus usuarios ya están claramente informados sobre los pasos de captura, ya que estas pantallas ayudan a reducir los errores de los usuarios y a mejorar la calidad de la captura.

{% hint style="info" %}
Tenga en cuenta que el `retryLimit` que configure aquí tendrá prioridad sobre el límite de reintentos que se haya establecido globalmente en sus [configuración de automatización](https://portal.complycube.com/automations).
{% endhint %}

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "documentCapture",

      // Habilita o deshabilita orientación adicional para el usuario
      "showGuidance": false,

      // Habilita la asistencia de ML durante la captura
      "useMLAssistance": true,

      // Establece un máximo de intentos de comprobación de calidad antes de subir
      "retryLimit": 1,

      // Habilita o deshabilita la capacidad de subir una imagen desde un archivo
      "liveCapture": false,

      // Establece los tipos de documentos y limita los países habilitados
      "documentTypes": {
        "passport": true,
        "driving_license": ['GB', 'US'],
      },
    },
    // ... otras etapas
  ],
};
```

### Captura NFC

El SDK móvil de ComplyCube admite lectura basada en NFC **chip RFID** la lectura de documentos de identidad equipados con chips integrados. Esto permite una extracción de datos segura y una autenticación documental de alta fiabilidad.

{% hint style="info" %}
Póngase en contacto con su **Gerente de cuenta** o [soporte](https://support.complycube.com/hc/en-gb/requests/new) para obtener acceso a nuestro SDK móvil con compatibilidad NFC.
{% endhint %}

#### Requisitos previos

{% tabs %}
{% tab title="iOS" %}
{% hint style="info" %}
Para usar esta función, tu aplicación debe tener la **`lectura de etiquetas de Comunicación de Campo Cercano`** habilitada. Para añadir esta capacidad a tu aplicación, consulta [la guía de Apple aquí](https://help.apple.com/xcode/mac/current/#/dev88ff319e7).
{% endhint %}

1. Instala el **CocoaPods Artifactory** plugin ejecutando el siguiente comando en tu terminal:<br>

   ```bash
   gem install cocoapods-art
   ```

2. Para añadir la biblioteca, copia las credenciales de tu repositorio en un `.netrc` archivo en tu directorio de inicio y configura el repositorio:<br>

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">pod repo-art add cc-cocoapods-release-local "https://complycuberepo.jfrog.io/artifactory/api/pods/cc-cocoapods-release-local"
   </code></pre>

   \
   Recuerda obtener tus credenciales de **JFrog** usando el **Configurar** botón [aquí](https://complycuberepo.jfrog.io/ui/repos/tree/General/cc-cocoapods-release-local).<br>

3. Añade repositorios de plugins e instala el pod usando tu `Podfile`:<br>

   ```ruby
    plugin 'cocoapods-art', :sources => [
      'cc-cocoapods-release-local',
      'trunk'
    ]
    ...
    platform :ios, '13.0' # O superior

    target 'YourApp' do
      use_frameworks!
      use_modular_headers!
      ...
      pod 'ComplyCubeMobileSDK', '2.0.x-nfc'
      ...
    en
   ```

4. Debes añadir las siguientes claves a tu aplicación `Info.plist` archivo:<br>

   ```xml
   <key>NFCReaderUsageDescription</key>
   <string>Requerido para leer documentos con NFC habilitado</string>
   ```

5. Para leer correctamente las etiquetas NFC, debes añadir las siguientes entradas al target de tu aplicación `Info.plist` archivo:<br>

   ```xml
   <key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
   <array>
     <string>12FC</string>
   </array>
   <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
   <array>
     <string>A0000002471001</string>
     <string>A0000002472001</string>
     <string>00000000000000</string>
     <string>D2760000850101</string>
     <string>E80704007F00070302</string>
     <string>A000000167455349474E</string>
     <string>A00000045645444C2D3031</string>
   </array>
   ```

6. Añade lo siguiente en tu `Runner.entitlements` archivo:<br>

   ```xml
   <key>com.apple.developer.nfc.readersession.formats</key>
   <array><string>TAG</string></array>
   ```

7. Para habilitar NFC al compilar tu app de iOS, pasa la `USE_CCNFC` variable de entorno durante la compilación:<br>

   ```bash
   USE_CCNFC=true flutter build ios
   ```

   \
   Para mantener esto habilitado en todas las compilaciones de iOS, añade la siguiente línea cerca de la parte superior de tu `ios/Podfile`:<br>

   ```ruby
   ENV['USE_CCNFC'] ||= 'true'
   ```

{% endtab %}

{% tab title="Android" %}

1. Comienza añadiendo tus credenciales de acceso para el repositorio del SDK habilitado para NFC de ComplyCube en el `gradle.properties` archivo de tu **aplicación móvil**:

```gradle
USE_NFC=true
artifactory_contextUrl=https://complycuberepo.jfrog.io/artifactory/cc-gradle-release
artifactory_user=<YOUR_USERNAME>
artifactory_password=<YOUR_PASSWORD>
```

> Reemplace <**YOUR\_USERNAME**> y <**YOUR\_PASSWORD**> con sus credenciales de ComplyCube Artifactory. Si no tiene acceso, póngase en contacto con el Soporte de ComplyCube para solicitar credenciales.

2. Luego, actualiza el nivel de tu proyecto `build.gradle` o `build.gradle.kts` archivo con la configuración Maven del repositorio del SDK de ComplyCube:

{% tabs %}
{% tab title="Groovy" %}

```javascript
repositories {
    google()
    mavenCentral()
    maven {
        url project.findProperty("artifactory_contextUrl")
        credentials {
            username = project.findProperty("artifactory_user")
            password = project.findProperty("artifactory_password")
        }
    }
}
```

{% endtab %}

{% tab title="Kotlin" %}

```python
repositories {
    google()
    mavenCentral()
    maven {
        url = uri(project.findProperty("artifactory_contextUrl") as String)
        credentials {
            username = project.findProperty("artifactory_user") as String?
            password = project.findProperty("artifactory_password") as String?
        }
    }
}
```

{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

#### Habilitar captura NFC

```dart
final settings = {
    // ... otros ajustes
    "stages" : [
      {
        "name": "documentCapture",
        // Añade esta propiedad para habilitar NFC
        "nfcEnabled": true
        ...
      },
      // ... otras etapas
    ]
}
```

### **Captura de dirección**

Esta etapa permite a los usuarios introducir manualmente su dirección residencial. Puede personalizarla para:

* Restringir la entrada a países específicos
* Activar o desactivar la función de autocompletado de direcciones para una introducción más rápida y precisa

```dart
final settings = {
  // ... otros ajustes
  stages: [
    {
      "name": "addressCapture",

      // Esto habilita nuestra función de autocompletado de direcciones
      "useAutoComplete": false,
      
      // Una lista de países aceptables para la captura de direcciones
      "allowedCountries": ['GB','US']
    },
    // ... otras etapas
  ],
};
```

### **Comprobante de domicilio**

Esta etapa permite a los clientes enviar un documento que verifique su dirección residencial. Puede configurar qué tipos de documentos se aceptan, como facturas de servicios públicos o extractos bancarios, y elegir si los clientes pueden cargar un archivo o si deben capturar el documento en vivo usando la cámara de su dispositivo.

{% hint style="info" %}
De forma predeterminada, esta etapa incluye la **etapa de captura de dirección** con el autocompletado habilitado para ayudar a los usuarios durante la entrada. El autocompletado se puede deshabilitar si no es necesario.
{% endhint %}

```dart
final settings = {
  // ... otros ajustes
  stages: [
    {
      "name": "poaCapture",

      // Cuando se deshabilita, el cliente se verá obligado a realizar una captura en vivo
      "liveCapture": false,
    },
    // ... otras etapas
  ],
};
```

### **Finalización**

Puede incluir una etapa de finalización al final del flujo para confirmar que el proceso se ha completado correctamente. Esta pantalla proporciona un punto final claro para el usuario y puede personalizarse para mostrar un mensaje de confirmación o los siguientes pasos.

```dart
final settings = {
  // ... otros ajustes
  "stages": [
    {
      "name": "complete",
      "heading": "¡Gracias!",
      "message": "Tu envío de KYC se ha completado.",
    },
    // ... otras etapas
  ],
};
```

## Identidad de marca

El SDK te permite personalizar la interfaz de usuario para que coincida con la identidad visual de tu aplicación. Puedes definir los colores principal y de acento durante la configuración para alinear el flujo de verificación con las directrices de tu marca. Obtén más información sobre nuestras **propiedades de apariencia** (ver más abajo).

```dart
final settings = {
  // ...
  "lookAndFeel": {
    // Color de fondo del botón de acción principal
    "primaryButtonBgColor": '#FFFFFF',
    
    // Fuerza al SDK al modo 'dark', 'light' o 'inherit'
    "uiInterfaceStyle": "dark"
  }
}
```

Para desactivar la visualización del encabezado en el widget del SDK de ComplyCube en **Android**, por favor inserte la siguiente línea en `styles.xml`:

```xml
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
  ...
  <item name="windowActionBar">false</item>
  <item name="windowNoTitle">true</item>
  ...
</style>
...
```

<details>

<summary>Propiedades de apariencia</summary>

<table><thead><tr><th width="371.70703125">Propiedad de apariencia</th><th>Descripción</th></tr></thead><tbody><tr><td><code>primaryButtonBgColor</code></td><td>Color de fondo del botón de acción principal.</td></tr><tr><td><code>primaryButtonTextColor</code></td><td>Color del texto del botón de acción principal.</td></tr><tr><td><code>primaryButtonBorderColor</code></td><td>Color del borde del botón de acción principal.</td></tr><tr><td><code>secondaryButtonBgColor</code></td><td>Color de fondo del botón secundario.</td></tr><tr><td><code>secondaryButtonPressedBgColor</code></td><td>Color de fondo del botón de acción secundaria al pulsarlo.<br><br><em>No es compatible con Android.</em></td></tr><tr><td><code>secondaryButtonTextColor</code></td><td>Color del texto del botón de acción secundaria.</td></tr><tr><td><code>secondaryButtonBorderColor</code></td><td>Color del borde del botón de acción secundaria.</td></tr><tr><td><code>documentTypeSelectorBgColor</code></td><td>Color del botón de selección del tipo de documento.</td></tr><tr><td><code>documentTypeSelectorBorderColor</code></td><td>Color del borde del botón de selección del tipo de documento.</td></tr><tr><td><code>documentTypeSelectorTitleTextColor</code></td><td>Color del texto del título de selección del tipo de documento.</td></tr><tr><td><code>documentTypeSelectorDescriptionTextColor</code></td><td>Color del texto de la descripción de selección del tipo de documento.</td></tr><tr><td><code>documentTypeSelectorIconColor</code></td><td>Color del icono de selección del tipo de documento.</td></tr><tr><td><code>bodyTextColor</code></td><td>Color del texto del cuerpo de la pantalla.</td></tr><tr><td><code>linkButtonTextColor</code></td><td>Color de los enlaces.<br><br><em>No es compatible con Android.</em></td></tr><tr><td><code>headingTextColor</code></td><td>Color del texto del título principal.</td></tr><tr><td><code>subheadingTextColor</code></td><td>Color del texto del subtítulo.</td></tr><tr><td><code>infoPanelTitleColor</code></td><td>Color del título del panel de información.</td></tr><tr><td><code>infoPanelDescriptionTextColor</code></td><td>Color del texto de la descripción del panel de información.</td></tr><tr><td><code>infoPanelBgColor</code></td><td>Color de fondo del panel de información.</td></tr><tr><td><code>infoPanelIconColor</code></td><td>Color del icono del panel de información.</td></tr><tr><td><code>errorPanelTitleColor</code></td><td>Color del título del panel de error.</td></tr><tr><td><code>errorPanelDescriptionTextColor</code></td><td>Color del texto de la descripción del panel de error.</td></tr><tr><td><code>errorPanelBgColor</code></td><td>Color de fondo del panel de error.</td></tr><tr><td><code>errorPanelIconColor</code></td><td>Color del icono del panel de error.</td></tr><tr><td><code>cameraButtonBgColor</code></td><td>Color de fondo del botón de captura de la cámara.</td></tr><tr><td><code>uiInterfaceStyle</code></td><td>Configura el SDK para usar el modo oscuro, el modo claro o el heredado del sistema.</td></tr></tbody></table>

</details>

## Localización

El SDK es compatible con varios idiomas, incluidos los que se enumeran a continuación.

{% columns %}
{% column %}

* Árabe - `ar` 🇦🇪
* Chino (simplificado) - `zh` 🇨🇳
* Chino (tradicional) - `hk` 🇨🇳
* Neerlandés - `nl` 🇳🇱
* Inglés - `en` 🇺🇸
* Francés - `fr` 🇫🇷
* Alemán - `de` 🇩🇪
* Hindi - `hi` 🇮🇳
* Indonesio -  `id` 🇮🇩
* Italiano - `it` 🇮🇹
  {% endcolumn %}

{% column %}

* Japonés -  `ja` 🇯🇵
* Coreano -  `ko` 🇰🇷
* Noruego - `no` 🇳🇴
* Polaco - `po` 🇵🇱
* Portugués - `pt` 🇵🇹
* Español - `es` 🇪🇸
* Sueco - `sv` 🇸🇪
* Tailandés -  `th` 🇹🇭
* Vietnamita -  `vi` 🇻🇳
* y más...
  {% endcolumn %}
  {% endcolumns %}

## Gestión de resultados

Para ejecutar comprobaciones de verificación, debe implementar los **éxito**, **cancelado**, y **error** callbacks.

Al completarse correctamente (`onSuccess`), puede activar [solicitudes de comprobación](/documentation/api-reference/core-resources/checks/create-a-check.md) desde su backend utilizando los IDs de recursos devueltos en el objeto de resultado. Estos IDs corresponden a los activos cargados (p. ej., documentos, selfies) y pueden usarse para iniciar comprobaciones de verificación a través de la API de ComplyCube.

Si el usuario abandona el flujo antes de completarlo, el `onCancelled` callback se invoca con un motivo descriptivo que indica por qué se canceló la sesión (p. ej., salida del usuario, tiempo de espera agotado, permiso denegado)

{% hint style="info" %}
En algunos casos, el cliente puede cancelar el flujo después de completar una o más etapas de captura. Si esto ocurre, es posible que cualquier dato capturado antes de la cancelación, como documentos o medios biométricos, ya se haya cargado en su registro de cliente.
{% endhint %}

Si el SDK encuentra un problema, el `onError` callback se activa con un `ComplyCubeError` objeto que contiene el tipo de error y el mensaje. Consulte los **códigos de error** (véase a continuación) para obtener una lista completa de los posibles casos de error.

```dart
void onSuccess(dynamic payload) {
  /*
    Gestionando los resultados exitosos.
    El flujo predeterminado (Documento de identidad + Foto en vivo + Comprobante de domicilio)
    devuelve una carga útil con esta estructura:
      {
        "documentIds":  ["xxxxx"],
        "livePhotoIds": ["xxxxx"],
        "poaIds":       ["xxxxx"],
      }
  */
}

void onCancelled(ComplyCubeCancelled event) {
  // Gestiona las cancelaciones (event.code, event.reason)
}

void onError(ComplyCubeError error) {
  // Gestiona los errores (error.code, error.message, error.details)
}

// 1. Suscríbete a los eventos una sola vez (p. ej., en initState).
ComplyCube.events.listen((event) {
  if (event is ComplyCubeSuccess)   onSuccess(event.payload);
  else if (event is ComplyCubeCancelled) onCancelled(event);
  else if (event is ComplyCubeError)     onError(event);
});

// 2. Inicia el flujo.
ComplyCube.start(settings);
```

<details>

<summary>Códigos de error</summary>

<table data-full-width="false"><thead><tr><th width="312.48828125">Tipo de error</th><th>Descripción</th></tr></thead><tbody><tr><td><code>BiometricStageCount</code></td><td>La configuración incluye duplicados <strong>foto de selfie</strong> o <strong>video de selfie</strong> etapas.</td></tr><tr><td><code>Cancelado</code></td><td>El cliente canceló el flujo y salió del SDK (activó la <code>onCancelled</code> devolución de llamada).</td></tr><tr><td><code>Conectividad</code></td><td>Se ha producido un error de red.</td></tr><tr><td><code>DocumentMandatory</code></td><td>Una <strong>etapa de documento</strong> es obligatorio según las etapas configuradas, pero no se ha incluido.</td></tr><tr><td><code>ExpiredToken</code></td><td>El token del SDK ha expirado. Genere un nuevo token y reinicie el flujo.</td></tr><tr><td><code>FlowError</code></td><td>Se produjo un error irrecuperable durante el flujo.</td></tr><tr><td><code>InvalidCountryCode</code></td><td>Se proporcionó un código de país no válido.</td></tr><tr><td><code>JailBroken</code></td><td>El SDK no puede ejecutarse en este dispositivo porque ha sido liberado de restricciones (jailbreak) o comprometido.</td></tr><tr><td><code>NoDiskAccess</code></td><td>El cliente denegó los permisos de acceso al disco requeridos por el SDK.</td></tr><tr><td><code>NoDocumentTypes</code></td><td>Una <strong>etapa de documento</strong> se inicializó sin especificar ningún tipo de documento.</td></tr><tr><td><code>NoResult</code></td><td>No se devolvió ningún resultado a la devolución de llamada. Si esto persiste, póngase en contacto con soporte.</td></tr><tr><td><code>NoUserConsent</code></td><td>El cliente no ha dado su consentimiento para continuar con el flujo del SDK.</td></tr><tr><td><code>NotAuthorized</code></td><td>El SDK intentó acceder a un extremo para el que no está autorizado.</td></tr><tr><td><code>Desconocido</code></td><td>Se produjo un error inesperado. Si esto ocurre repetidamente, contacte con soporte.</td></tr><tr><td><code>UnsupportedCountryTypeCombination</code></td><td>La combinación de país y tipo de documento seleccionada no es compatible.</td></tr><tr><td><code>UnsupportedDocumentType</code></td><td>El tipo de documento proporcionado no es compatible.</td></tr><tr><td><code>UploadError</code></td><td>Se produjo un error al cargar un documento o una selfie.</td></tr><tr><td><code>UploadRequireGuidance</code></td><td>Si <code>useLiveCaptureOnly</code> está configurado en <code>false</code>, la guía debe habilitarse configurando <code>isGuidanceEnabled</code> en <code>true</code>.</td></tr></tbody></table>

</details>

## Seguimiento de eventos

El SDK registra una variedad de **eventos** durante todo el flujo de verificación, cubriendo todas las interacciones clave del usuario en cada etapa. Consulte a continuación la lista de eventos.

Si necesita implementar analíticas personalizadas, puede conectarse a estos eventos y activar su propia lógica de seguimiento en consecuencia.

Para incorporar tu propio seguimiento, define una función y aplícala usando el `onCustomEvent` propiedad al inicializar el widget de Flutter:

```dart
void onCustomEvent(ComplyCubeCustomEvent event){
  switch(event.name){
    case 'BIOMETRICS_STAGE_SELFIE_CAMERA':
      print("El cliente llegó a la cámara de captura para una selfie")
      break;
  }
}

ComplyCubeWidget(
  settings: settings,
  onCustomEvent: onCustomEvent,
  // ...
),
```

<details>

<summary>Eventos</summary>

| Evento                                                                                                                                                                                                                                           |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p><code>INTRODUCCIÓN</code><br><br>El cliente llegó a la pantalla de introducción.</p>                                                                                                                                                          |
| <p><code>ETAPA\_DE\_CONSENTIMIENTO</code><br><br>El cliente llegó a la pantalla de consentimiento.</p>                                                                                                                                           |
| <p><code>ADVERTENCIA\_DE\_ETAPA\_DE\_CONSENTIMIENTO</code><br><br>El cliente intentó salir sin dar su consentimiento.</p>                                                                                                                        |
| <p><code>PERMISO\_DE\_ACCESO\_A\_LA\_CÁMARA</code><br><br>El cliente llegó a la pantalla de solicitud de permiso de la cámara.</p>                                                                                                               |
| <p><code>ETAPA\_DE\_GUÍA\_DE\_CAPTURA\_DE\_DOCUMENTO</code><br><br>El cliente llegó a la pantalla de guía de captura de documentos.</p>                                                                                                          |
| <p><code>ETAPA\_DE\_TIPO\_DE\_DOCUMENTO</code><br><br>El cliente llegó a la pantalla de selección del tipo de documento para una captura de documento.</p>                                                                                       |
| <p><code>ETAPA\_DE\_SELECCIÓN\_DE\_PAÍS</code><br><br>El cliente llegó a la pantalla de selección de país para una captura de documento.</p>                                                                                                     |
| <p><code>ETAPA\_DE\_CÁMARA\_DE\_DOCUMENTO\_DE\_UNA\_CARA</code><br><br>El cliente llegó a la etapa de captura con cámara para un documento de identificación de una sola cara.</p>                                                               |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DE\_DOCUMENTO\_DE\_UNA\_CARA</code><br><br>El cliente llegó a la pantalla de captura manual con cámara de un documento de identificación de una sola cara.</p>                                               |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DE\_DOCUMENTO\_DE\_UNA\_CARA</code><br><br>El cliente llegó a la pantalla de vista previa de calidad para un documento de identificación de una sola cara.</p>                                        |
| <p><code>ETAPA\_DE\_CÁMARA\_DELANTERA\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de captura con cámara para la cara frontal de un documento de identificación de dos caras.</p>                                 |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DELANTERA\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de captura manual con cámara para la cara frontal de un documento de identificación de dos caras.</p>                  |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DELANTERA\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de vista previa de calidad para la cara frontal de un documento de identificación de dos caras.</p>             |
| <p><code>ETAPA\_DE\_CÁMARA\_POSTERIOR\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de captura con cámara para la cara posterior de un documento de identificación de dos caras.</p>                               |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_POSTERIOR\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de captura manual con cámara para la cara posterior de un documento de identificación de dos caras.</p>                |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_POSTERIOR\_DE\_DOCUMENTO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la pantalla de vista previa de calidad para la cara posterior de un documento de identificación de dos caras.</p>           |
| <p><code>ETAPA\_DE\_GUÍA\_DE\_CAPTURA\_DE\_SELFIE</code><br><br>El cliente llegó a la pantalla de guía de captura de selfie.</p>                                                                                                                 |
| <p><code>ETAPA\_DE\_CÁMARA\_DE\_SELFIE</code><br><br>El cliente llegó a la pantalla de cámara para capturar la foto de selfie.</p>                                                                                                               |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DE\_SELFIE</code><br><br>El cliente llegó a la pantalla de cámara para capturar manualmente la foto de selfie.</p>                                                                                           |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DE\_SELFIE</code><br><br>El cliente llegó a la pantalla de revisión de la foto capturada de la selfie.</p>                                                                                            |
| <p><code>ETAPA\_DE\_CÁMARA\_DE\_VIDEO\_SELFIE</code><br><br>El cliente llegó a la pantalla de cámara para selfie en video.</p>                                                                                                                   |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DE\_VIDEO\_SELFIE</code><br><br>El cliente llegó a la pantalla de captura manual con cámara para una selfie en video.</p>                                                                                    |
| <p><code>ETAPA\_DE\_ACCIÓN\_DE\_VIDEO\_SELFIE\_UNO</code><br><br>El cliente llegó a la primera acción en una captura de selfie en video.</p>                                                                                                     |
| <p><code>ETAPA\_DE\_ACCIÓN\_DE\_VIDEO\_SELFIE\_DOS</code><br><br>El cliente llegó a la segunda acción en una captura de selfie en video.</p>                                                                                                     |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DE\_VIDEO\_SELFIE</code><br><br>El cliente llegó a la pantalla de cámara para captura manual de selfie en video.</p>                                                                                  |
| <p><code>ETAPA\_DE\_GUÍA\_DE\_CAPTURA\_DE\_COMPROBANTE\_DE\_DOMICILIO</code><br><br>El cliente llegó a la pantalla de guía de captura de comprobante de domicilio.</p>                                                                           |
| <p><code>ETAPA\_DE\_TIPO\_DE\_DOCUMENTO\_DE\_COMPROBANTE\_DE\_DOMICILIO</code><br><br>El cliente llegó a la pantalla de selección del tipo de documento para una captura de comprobante de domicilio.</p>                                        |
| <p><code>ETAPA\_DE\_SELECCIÓN\_DE\_PAÍS\_DE\_COMPROBANTE\_DE\_DOMICILIO</code><br><br>El cliente llegó a la pantalla de selección de país para una captura de comprobante de domicilio.</p>                                                      |
| <p><code>ETAPA\_DE\_CÁMARA\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_UNA\_CARA</code><br><br>El cliente llegó a la etapa de captura con cámara para un comprobante de domicilio de una sola cara.</p>                                                 |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_UNA\_CARA</code><br>El cliente llegó a la etapa de captura manual con cámara para un comprobante de domicilio de una sola cara.</p>                                      |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_UNA\_CARA</code><br><br>El cliente llegó a la pantalla de vista previa de calidad para un comprobante de domicilio de una sola cara.</p>                          |
| <p><code>ETAPA\_DE\_CÁMARA\_DELANTERA\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la etapa de captura con cámara para la cara frontal de un comprobante de domicilio de dos caras.</p>                      |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_DELANTERA\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br>El cliente llegó a la etapa de captura manual con cámara para la cara frontal de un comprobante de domicilio de dos caras.</p>           |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_DELANTERA\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br>El cliente llegó a la pantalla de vista previa de calidad para la cara frontal de un comprobante de domicilio de dos caras.</p>   |
| <p><code>ETAPA\_DE\_CÁMARA\_POSTERIOR\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br><br>El cliente llegó a la etapa de captura con cámara para la cara posterior de un comprobante de domicilio de dos caras.</p>                    |
| <p><code>ETAPA\_DE\_CÁMARA\_MANUAL\_POSTERIOR\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br>El cliente llegó a la etapa de captura manual con cámara para la cara posterior de un comprobante de domicilio de dos caras.</p>         |
| <p><code>ETAPA\_DE\_REVISIÓN\_DE\_CALIDAD\_POSTERIOR\_DE\_COMPROBANTE\_DE\_DOMICILIO\_DE\_DOS\_CARAS</code><br>El cliente llegó a la pantalla de vista previa de calidad para la cara posterior de un comprobante de domicilio de dos caras.</p> |
| <p><code>ETAPA\_DE\_FINALIZACIÓN</code><br><br>El cliente ha llegado a la pantalla de finalización.</p>                                                                                                                                          |

</details>

## Gestión de vencimiento del token

Para gestionar la expiración del token de forma fluida, puedes proporcionar una función de devolución de llamada que genere un nuevo token del SDK cuando sea necesario. Esto permite que el flujo continúe sin interrupciones, sin que el usuario tenga que reiniciar la sesión manualmente.

```dart
String onTokenExpiry(String token){
  // Inserte aquí el código personalizado de renovación del token
}

ComplyCubeWidget(
  settings: settings,
  onTokenExpiry: onTokenExpiry,
  // ...
),
```


---

# 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.complycube.com/documentation/sdks/sdks-es/integraciones-moviles/sdk-de-flutter/integracion-basada-en-comprobaciones.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.
