# Guía de Pix Biometria (iOS SDK + API)

Próximo Lanzamiento
Esta documentación cubre características de nuestro próximo lanzamiento. Aunque la funcionalidad principal y el flujo de trabajo descrito aquí permanecerán sin cambios, puede que notes algunas mejoras antes del lanzamiento final, tales como:

- Actualizaciones y optimizaciones del iOS SDK
- Mejoras en la documentación (enlaces, terminología, diagramas)
- Actualizaciones de referencia de la API para los endpoints de inscripción


Con Pix Biometria de Belvo, la recolección de pagos de los usuarios se vuelve sencilla, eliminando la necesidad de que los usuarios naveguen a su institución financiera para aprobar cada solicitud de pago individual.

El primer paso para habilitar la recolección de pagos biométricos es **inscribir** el dispositivo del usuario con su institución. Durante la inscripción, los datos clave sobre el dispositivo y las credenciales de clave pública del usuario se registran de manera segura con su institución, asegurando que los pagos futuros puedan ser confirmados usando solo la autenticación biométrica. Una vez que la inscripción esté completa, puedes comenzar a solicitar pagos directamente desde el dispositivo del usuario.

En esta guía, te llevaremos a través de cada paso, desde la inscripción del dispositivo hasta la iniciación exitosa de una solicitud de pago en un dispositivo iOS.

Uso de SDK + API
Esta guía demuestra el uso tanto del SDK de Belvo como de la API para inscribir dispositivos así como para realizar pagos. Sin embargo, puedes completar todo el flujo usando solo el SDK de Belvo. Para más información, consulta nuestra guía Pix Biometria iOS SDK Only.

## Requisitos previos

Antes de comenzar, asegúrate de tener:

1. **Generadas tus claves de la API de Belvo Payments**
2. **Configurados los Webhooks** para recibir actualizaciones de estado de pagos y registros
3. **Generado un SDK Access Token** (ver abajo)
4. **Instalado el Belvo iOS SDK** (ver abajo)
5. **Creado un Belvo Customer** para cada usuario que deseas registrar


### Token de Acceso del SDK

Autenticación del SDK
El SDK de Pix Biometria requiere un token de acceso para autenticar las solicitudes de la API. Genera este token desde tu servidor backend y pásalo al SDK durante la inicialización.

Genera un token de acceso del SDK desde tu backend:

```bash
POST https://api.belvo.com/payments/api/widget-token/
Authorization: Basic <base64_encoded_secret_id:secret_password>
Content-Type: application/json
```

```json
{
  "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

Mejores Prácticas para Tokens
Nunca codifiques tokens directamente en tu aplicación. Siempre genéralos del lado del servidor e implementa un almacenamiento seguro y lógica de actualización.

### Instalación del SDK

**Requisitos Mínimos**

- **iOS**: 15.0 o superior
- **Swift**: 5.0 o superior


**Instrucciones:**

Para integrar el Belvo Biometric PIX SDK en tu proyecto de Xcode usando Swift Package Manager:

1. En Xcode, selecciona **File** → **Add Packages...**.
2. Ingresa la URL del repositorio del paquete: `https://github.com/belvo-finance-opensource/biometric-pix-ios-sdk`.
3. Selecciona los requisitos de versión y haz clic en **Add Package**.
4. Elige el producto **BiometricPixSDK** y haz clic en **Add Package**.


**Agrega los derechos requeridos al archivo de derechos de tu aplicación:**

```xml
<key>com.apple.developer.associated-domains</key>
 <array>
  <string>webcredentials:belvo.com</string>
 </array>
```

**Agrega la descripción del uso de la ubicación en tu archivo `Info.plist`:**

```xml
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>Esta aplicación utiliza la ubicación para propósitos de seguridad y prevención de fraude.</string>
```

**Comparte tu Team ID y Bundle Identifier con Belvo en el siguiente formato:**

```shell
   ## Formato
   TEAM_ID.BUNDLE_ID

   ## Ejemplo
   ABCDEFGHIJ.com.yourcompany.appname
```

## Inscripción

Crear un Cliente Primero
Antes de crear una inscripción, debes crear un cliente utilizando la API de Belvo (para tener un `customer.id` con el cual asociar la inscripción). Para obtener detalles sobre cómo crear un cliente, consulta la solicitud Crear Cliente (Brasil), asegurándote de seleccionar el cuerpo de la solicitud **V1 - Crear Cliente**.

La inscripción es el proceso de registrar el dispositivo de un usuario en su institución para permitir pagos biométricos para un comerciante determinado. Durante el proceso, utilizarás una **combinación** del SDK de iOS de Belvo Payments y la API para recuperar detalles clave sobre el dispositivo, así como los datos públicos biométricos.

1. **Listar Instituciones:** Solicita al usuario que seleccione su institución financiera deseada para inscribirse, utilizando la API de Belvo para mostrar las opciones disponibles.
2. **Solicitar Permisos de Ubicación y Recopilar Señales de Riesgo:** Solicita al usuario los permisos necesarios y recopila señales de riesgo, incluido el ID del dispositivo.
3. **Crear y Actualizar Inscripción:** Envía las señales de riesgo recopiladas, junto con el ID del cliente, el ID de la institución y una URL de callback, al servidor de Belvo para crear la inscripción. Luego, redirige al usuario a la aplicación de su institución para su aprobación. Una vez que sean redirigidos de vuelta a tu URL de callback con detalles, envía estos a Belvo para actualizar el estado de la inscripción.
4. **Consultar Opciones de FIDO:** Consulta continuamente la API de Belvo (`GET /enrollments/{id}/fido-registration-options/`) para recuperar las opciones FIDO necesarias para el registro biométrico.
⚠️ **Estrategia de Consulta:** Recomendamos consultar nuestro servidor cada dos segundos durante un máximo de dos minutos. Si no se recibe respuesta dentro de este período, instruye al usuario para que lo intente de nuevo.
5. **Solicitar Datos Biométricos:** Toma las opciones FIDO de la API de Belvo y utiliza el método `startRegistration(fidoOptions)` del SDK de iOS de Belvo para solicitar al usuario su gesto biométrico.
6. **Finalizar Inscripción:** Envía los datos públicos biométricos a Belvo utilizando `POST /enrollments/{id}/confirm/`. Después de eso, consulta `GET /enrollments/{id}/` hasta recibir una respuesta (estado de inscripción = `SUCCEEDED` o `FAILED`).


```mermaid
sequenceDiagram
    autonumber

    participant EndUser
    participant ClientAppBackend
    participant BiometricPixSDK
    participant Payments
    participant BankAPP

    Note over EndUser,BankAPP: 0. Solicitar al usuario que seleccione la institución para inscribirse (API de Belvo)

    ClientAppBackend ->> Payments: /institutions/
    Payments -->> ClientAppBackend: Lista de instituciones
    ClientAppBackend ->> EndUser: Mostrar lista de instituciones
    EndUser -->> ClientAppBackend: Institución seleccionada

    Note over EndUser,BankAPP: 1. Solicitar Permisos de Ubicación y Recopilar Señales de Riesgo (SDK de iOS)

    BiometricPixSDK ->> EndUser: requestPermission()
    EndUser -->> BiometricPixSDK: Otorga permiso para recopilar señales de riesgo
    ClientAppBackend ->> BiometricPixSDK: collectRiskSignals(accountTenure)
    BiometricPixSDK -->> ClientAppBackend: Devuelve riskSignals + deviceId (encriptado)
    ClientAppBackend ->> ClientAppBackend: Persiste deviceId (encriptado)

    Note over EndUser,BankAPP: 2. Enviar Señales de Riesgo a Belvo (API de Belvo)

    ClientAppBackend ->> Payments: POST /enrollments/ (riskSignals, callback_url)
    Payments -->> ClientAppBackend: 201 Created (enrollment_id, redirect_url)
    ClientAppBackend ->> ClientAppBackend: Persiste enrollment_id asociado con deviceId (encriptado)

    Note over EndUser,BankAPP: 3. Redirigir al usuario a su APP y actualizar inscripción

    ClientAppBackend ->> EndUser: Redirigir a BankAPP (usando el redirect_url)
    EndUser ->> BankAPP: Aprueba inscripción
    BankAPP ->> ClientAppBackend: La institución redirige a callback_url con detalles en parámetros de consulta
    ClientAppBackend ->> Payments: Actualizar inscripción con valores recibidos usando POST /enrollments/complete-redirection/
    Payments -->> ClientAppBackend: Devuelve carga útil de inscripción actualizada

    Note over EndUser,BankAPP: 4. Consultar API de Belvo para opciones de FIDO

    ClientAppBackend ->> Payments: Consultar GET /enrollments/{id}/fido-registration-options/
    Payments -->> ClientAppBackend: Devuelve fido_options

    Note over EndUser,BankAPP: 5. Solicitar Datos Biométricos (SDK de iOS)

    ClientAppBackend ->> BiometricPixSDK: startRegistration(fidoOptions)
    BiometricPixSDK ->> EndUser: Solicitar datos biométricos
    EndUser -->> BiometricPixSDK: Proporciona biométrico (cara/huella/PIN)
    BiometricPixSDK -->> ClientAppBackend: encodedId, rawId, encodedAttestationObject, encodedClientDataJSON

    Note over EndUser,BankAPP: 6. Enviar biométricos para finalizar inscripción y consultar respuesta

    ClientAppBackend ->> Payments: POST /enrollments/{id}/confirm/ (attestationObject, clientDataJSON, credential)
    Payments -->> ClientAppBackend: 204 - No Content
    ClientAppBackend ->> Payments: Consultar GET /enrollments/{id}/
    Payments -->> ClientAppBackend: status = SUCCEEDED
```

## Solicitar al usuario que seleccione la institución para inscribirse (Belvo API)

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `getPaymentInstitutions()` que simplifica la obtención de instituciones. Este método maneja la llamada a la API internamente y devuelve una lista de objetos `Institution`. Consulte la sección de referencia del método SDK para más detalles.

En tu aplicación, solicita a tu usuario que seleccione la institución donde desea inscribir el dispositivo. Utiliza la solicitud Listar todas las instituciones de pago para obtener una lista de todas las posibles instituciones. Una vez que el usuario seleccione la institución, guarda el id de la institución (requerido en el paso Enviar Señales de Riesgo a Belvo (API)).

## Solicitar permisos de ubicación y recopilar señales de riesgo (iOS SDK)

A continuación, en tu aplicación, necesitarás realizar las siguientes llamadas:

### requestPermission()

Este método `requestPermission()` crea y lanza una solicitud de permiso para permisos de ubicación y estado del teléfono.

```swift
import SwiftUI
import BiometricPixSDK
import Foundation

struct PermissionRequestExample: View {
    @State private var permissionGranted: Bool? = nil
    private let sdk = BiometricPixSDK()

    private func requestPermission() {
        sdk.requestPermission { granted in
            DispatchQueue.main.async {
								// Si es necesario, convertir granted a Bool
                permissionGranted = granted as? Bool
								// Si es necesario, manejar la UI
            }
        }
    }
}
```

Cuando el usuario concede su permiso, puedes entonces extraer las señales de riesgo del dispositivo usando `collectRiskSignals(accountTenure)`.

### collectRiskSignals(accountTenure)

El método `collectRiskSignals(accountTenure)` recopila datos completos de huellas digitales del dispositivo y señales de seguridad. Los datos recopilados incluyen ID del dispositivo, estado de seguridad, información de hardware y señales de comportamiento, que son cruciales para que la institución realice evaluaciones de riesgo y detección de fraude. El método devuelve un objeto RiskSignals que necesitas guardar y enviar a los servidores de Belvo en una llamada de API. Además, necesitas persistir el valor de `deviceId` que el objeto RiskSignals devuelve para que más tarde puedas asociarlo con el ID de Inscripción (más adelante, al listar Inscripciones, necesitas proporcionar el `deviceID` para recibir todas las Inscripciones).

Parámetro accountTenure
En el argumento `accountTenure`, debes pasar la fecha en que el usuario fue creado como Cliente en la API de Belvo, en formato `YYYY-MM-DD`.

Esto se deriva del timestamp created_at del Cliente. Sin embargo, solo necesitas enviar los primeros 10 caracteres correspondientes al año, mes y día (`YYYY-MM-DD`). Una expresión regular útil para extraer esto del parámetro `created_at` podría ser: `\d{4}-\d{2}-\d{2}`.

```swift
import SwiftUI
import BiometricPixSDK
import Foundation

struct RiskSignalsView: View {
    private let sdk = BiometricPixSDK()

    private func collectRiskSignals() {
        do {
            // Recopilar señales de riesgo con la fecha de creación del usuario
            signals = sdk.collectRiskSignals(
                accountTenure: "YYYY-MM-DD" // [!code highlight]
            )
        } catch {
            // Manejar errores que puedan ocurrir durante la recopilación de señales de riesgo.
            // Los posibles errores incluyen:
            // - Formato inválido de `accountTenure`
            // - Problemas de conectividad de red
            // Considera registrar el error o mostrar un mensaje apropiado al usuario.
        }
    }
}
```

Una vez que tengas las señales de riesgo y el ID del dispositivo, puedes enviar esta información a Belvo utilizando el método Create Enrollment.

## Crear Inscripción Usando Señales de Riesgo (API)

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `createEnrollment()` que simplifica el proceso de inscripción. Este método:

- Recoge automáticamente señales de riesgo internamente
- Acepta CPF directamente (no es necesario crear el Cliente primero)
- Maneja la llamada a la API para crear la inscripción
- Devuelve un objeto `Enrollment` enriquecido con datos de la institución


**Ejemplo:**

```swift
let enrollment = sdk.createEnrollment(
    cpf: "12345678900",
    institution: institutionId,
    accountTenure: "2024-01-15",
    callbackUrl: "https://myapp.com/callback"
)
```

```curl
POST /enrollments/
```

```json
// Cuerpo de la Solicitud
{
    "type": "open_finance_biometric_pix",
    "details": {
        "customer": "{{created_customer_uuid}}",
        "institution": "{{selected_institution_uuid}}",
        "name": "Nombre para la inscripción",
        "platform": "IOS",
        "callback_url": "{{https://deeplink_to_your_application}}",
        "risk_signals": {} // [!code highlight]
    }
}
```

| Parámetro | Tipo | Descripción |
|  --- | --- | --- |
| `type` | string (enum) | El tipo de inscripción. Para Pix Biometria, esto debe establecerse en `open_finance_biometric_pix`. |
| `details` | object | Detalles sobre la inscripción del dispositivo. |
| `details.customer` | string (uuid) | El ID de Belvo para tu usuario. |
| `details.institution` | string (uuid) | El ID de Belvo para la institución que tu usuario seleccionó para la inscripción. |
| `details.callback_url` | string (uri) | El deeplink a donde tu usuario debe ser redirigido en tu aplicación después de que aprueben la inscripción en la aplicación de su institución. Debe ser compatible con HTTPS. |
| `details.name` | string | Un nombre legible para la inscripción. |
| `details.platform` | string | La plataforma a la que se refiere esta inscripción. Para dispositivos iOS, esto debe establecerse en `IOS`. |
| `details.risk_signals` | object | El objeto `RiskSignals` (convertido a JSON) que recibiste después de usar el método `collectRiskSignals`. |


Registra tu callback_url
El `callback_url` que proporciones **debe** estar registrado en tus applinks. Para obtener detalles sobre cómo registrar tu URL de callback, consulta la documentación de Apple sobre applinks.

En la respuesta, recibirás un `redirect_url` que necesitas mostrar a tu usuario para que puedan ser redirigidos a su institución para confirmar su inscripción.

```json
// 201 Created
{
  "id": "82666cde-3f80-4350-b0f7-24cb8e9294c9",
  "created_by": "56689ef8-4c92-44ae-b2c1-60505da4a7e1",
  "created_at": "2024-11-26T11:20:57.389056Z",
  "updated_at": "2024-11-26T11:20:57.389056Z",
  "type": "open_finance_biometric_pix",
  "status": "PENDING",
  "details": {
    "status": "AWAITING_ACCOUNT_HOLDER_VALIDATION",
    "customer": "f78b14f3-5c1a-409a-966f-7b052b067cf0",
    "institution": "188716fb-39ad-44a7-a992-6c278d2b24a4",
    "platform": "IOS",
    "name": "First Enrollment",
    "callback_url": "deeplink-to-your-application",
    "redirect_url": "https://www.user-banking-institituon.com/?enrollment_request=true...", // [!code highlight]
    "risk_signals": "*****"
  }
}
```

## Redirigir al usuario a su APP y actualizar la inscripción

Ahora necesitas redirigir a tu usuario a su institución usando el `redirect_url` para que puedan confirmar el proceso de inscripción. Durante el proceso, iniciarán sesión en su institución, revisarán la solicitud de inscripción y luego la autorizarán. Una vez que el usuario autorice la inscripción, la institución los redirigirá de vuelta al `callback_url` que proporcionaste.

Ejemplo de Éxito
```json
https://redirect.clientApplication.com/
	?state=<state>
	&code=<code>
	&id_token=<long_id_token>
```

Ejemplo de Error
```json
https://redirect.clientApplication.com/
	?state=<state>
	&error=<error>
	&error_description=<error_description>
```

La institución pasará datos en los parámetros de consulta que debes reenviar a Belvo usando la solicitud de API **Update Enrollment State**. Recomendamos transformar los parámetros de consulta en un objeto JSON y enviarlo directamente a Belvo.

## Actualizar Estado de Inscripción

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `completeEnrollmentAfterRedirection()` que simplifica el manejo de callbacks OAuth:

- Acepta la URL completa del callback y automáticamente analiza los parámetros
- O acepta parámetros individuales `state`, `code` y `idToken`
- Maneja la llamada a la API internamente
- Devuelve un objeto `Enrollment` enriquecido


**Ejemplo:**

```swift
// Opción 1: Analizar automáticamente la URL del callback
let enrollment = sdk.completeEnrollmentAfterRedirection(
    callbackUrl: callbackUrl // URL completa con parámetros de consulta
)

// Opción 2: Proporcionar parámetros individualmente
let enrollment = sdk.completeEnrollmentAfterRedirection(
    state: state,
    code: code,
    idToken: idToken
)
```

Con el valor de la cadena de consulta guardado como un objeto JSON, puedes hacer la siguiente solicitud:

```json
POST /enrollments/complete-redirection/
```

Ejemplo de Éxito
```json Cuerpo de Solicitud de Éxito
{
    "state": "{{state}}",
    "code": "{{code}}",
    "id_token": "{{id_token}}",
}
```

En el caso de que haya sido un callback exitoso, en la respuesta de la solicitud el `status` de la inscripción seguirá configurado como `PENDING`.

```json Actualización de Estado de Inscripción Exitosa
// 200 OK
{
    "id": "{{enrollment.id}}", // [!code highlight]
    "type": "open_finance_biometric_pix",
    "status": "PENDING",  // [!code highlight]
    "details": {
        "callback_url": "https://merchant.com/enrollment-success/",
        "customer": "{{customer.id}}",
        "expires_at": "2022-10-31T00:00:00Z",
        "institution": "uuid",
        "name": "My Enrollment",
        "payer_information": {
            "bank_account": {
                "institution_id": "{{institution.id}}",
                "agency": "1234",
                "number": "*****6789",
                "account_type": "CHECKINGS"
            }
        },
        "platform": "IOS",
        "redirect_url": "https://example.com/redirect-enrollment/",
        "risk_signals": "*******",
        "status": "AWAITING_ACCOUNT_HOLDER_VALIDATION"
    },
    "external_id": null,
    "metadata": {},
    "status_reason_code": null,
    "status_reason_message": null,
    "created_by": "{{belvo_client.id}}",
    "created_at": "{{timestamp}}",
    "updated_at": "{{timestamp}}"
}
```

La institución ahora procesará los datos de inscripción y proporcionará a Belvo las Opciones FIDO que se requieren para generar el desafío biométrico. Necesitarás consultar nuestra API para recuperar estos datos y luego solicitar datos biométricos de tu usuario.

Ejemplo de Error
```json
{
    "state": "{{state}}",
    "error": "{{error}}",  
    "error_description": "{{error_description}}"
}
```

En el caso de que haya sido un callback de error, nuestra API aún responderá con un `200 - OK` con el `status` de la inscripción configurado como `FAILED`. Además, el `status_reason_code` y el `status_reason_message` se establecerán para proporcionar más información sobre el fallo.

```json Actualización de Estado de Inscripción Fallida
// 200 OK
{
    "id": "{{enrollment.id}}", // [!code highlight]
    "type": "open_finance_biometric_pix",
    "status": "FAILED",  // [!code highlight]
    "details": {
        "callback_url": "https://merchant.com/enrollment-success/",
        "customer": "{{customer.id}}",
        "expires_at": "2022-10-31T00:00:00Z",
        "institution": "uuid",
        "name": "My Enrollment",
        "payer_information": {
            "bank_account": {
                "institution_id": "{{institution.id}}",
                "agency": "1234",
                "number": "*****6789",
                "account_type": "CHECKINGS"
            }
        },
        "platform": "IOS",
        "redirect_url": "https://example.com/redirect-enrollment/",
        "risk_signals": "*******",
        "status": "AWAITING_ACCOUNT_HOLDER_VALIDATION"
    },
    "external_id": null,
    "metadata": {},
    "status_reason_code": "insufficient_funds", // [!code highlight]
    "status_reason_message": "No funds", // [!code highlight]
    "created_by": "{{belvo_client.id}}",
    "created_at": "{{timestamp}}",
    "updated_at": "{{timestamp}}"
}
```

## Consultar la API de Belvo para opciones FIDO (API)

Método de Conveniencia del SDK con Auto-Sondeo
El SDK de iOS proporciona un método `getFidoRegistrationOptions()` que simplifica la obtención de opciones FIDO:

- Sondea automáticamente cada 1 segundo durante hasta 5 minutos
- Devuelve `FidoRegistrationOptions` cuando está listo, o `nil` si el sondeo se agota
- Elimina la necesidad de lógica de sondeo manual


**Ejemplo:**

```swift
let fidoOptions = sdk.getFidoRegistrationOptions(enrollmentId: enrollmentId)
if let fidoOptions = fidoOptions {
    // Opciones listas, proceder con el registro
    sdk.startRegistration(fidoResponseString: fidoOptions.toJsonString(), callback: self)
} else {
    // El sondeo falló o se agotó el tiempo
}
```

Consejos para Sondeo Manual
Si implementas sondeo manual: Envía una solicitud cada dos segundos hasta que recibas una respuesta o pasen dos minutos sin respuesta. Si no recibes respuesta después de dos minutos, muestra una pantalla de "Intenta de nuevo" a tu usuario y reinicia el proceso. En segundo plano, la Inscripción pasará al `status` = `FAILED`.

Después de recibir la respuesta exitosa de la solicitud **Actualizar Estado de Inscripción**, necesitas sondear el siguiente endpoint para recibir las opciones de registro FIDO necesarias para solicitar datos biométricos.

```bash
GET /enrollments/{enrollment_id}/fido-registration-options/
```

Recibirás la siguiente respuesta `200 - OK` de nuestra API. Asegúrate de guardar el objeto (`fidoOptions`) ya que es un parámetro requerido para el método `startRegistration()` del SDK.

```json
// 200 OK
{
    "rp": {
        "id": "belvo.com",
        "name": "Raidiam Mockbank - Pipeline NRJ"
    },
    "user": {
        "id": "a5bd0ef9-f8ab-41a2-b968-489761a91de6",
        "name": "Ralph Bragg",
        "displayName": "Ralph Bragg"
    },
    "challenge": "R3dsT2REOE5oZ25JbVE",
    "pubKeyCredParams": [
        {
            "alg": -257,
            "type": "public-key"
        },
        {
            "alg": -7,
            "type": "public-key"
        }
    ],
    "extensions": {
        "appid": "true"
    }
}
```

## Solicitud de Biometría (iOS SDK)

Con la carga útil recibida, necesitas usar el método **startRegistration(fidoOptions)**. Este método inicia el registro de credenciales biométricas utilizando protocolos FIDO2. Procesa las opciones de registro FIDO (una cadena JSON) recibidas de tu servidor backend y lanza el flujo de autenticación biométrica nativa del dispositivo (por ejemplo, huella digital o escaneo facial).

```swift
import Foundation
import BiometricPixSDK

class FidoRegistrationViewModel : NSObject, ObservableObject {
    private let sdk = BiometricPixSDK()

    func startRegistration(fidoOptions: String) {
        do {
            sdk.startRegistration(
                fidoResponseString: fidoOptions, // [!code highlight]
                callback: self // Instancia de Callback
            )
        } catch {
            // Manejar errores
        }
    }
}

// Implementación del callback para el registro
extension FidoRegistrationViewModel: FidoRegistrationCallback {
    func onError(error: String) {
            // Manejar errores de registro
    }

    func onSuccess(response attestationResponse: AttestationResponse) {
            // Manejar registro exitoso
            // El objeto attestationResponse contiene los datos necesarios para el siguiente paso.
            let encodedId = attestationResponse.encodedId
            let rawId = attestationResponse.rawId
            let encodedAttestationObject = attestationResponse.encodedAttestationObject
            let encodedClientDataJSON = attestationResponse.encodedClientDataJSON
            
            // Persistir estos valores para enviarlos a tu backend.
    }
}
```

Al usar este modelo de vista en vistas de SwiftUI, decláralos como propiedades @ObservedObject para asegurar que no sean destruidos durante las re-renderizaciones de la vista. Esto es crítico para que los callbacks funcionen correctamente.

```swift
import SwiftUI

struct MyView: View {
    @ObservedObject var registrationViewModel = FidoRegistrationViewModel()
// ...
}
```

Necesitas almacenar los siguientes valores en variables ya que se utilizan para confirmar la Inscripción en el siguiente paso:

- `encodedId`
- `rawId`
- `encodedAttestationObject`
- `encodedClientDataJSON`


## Enviar biometría para finalizar el registro y consultar la respuesta (API)

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `confirmEnrollment()` que simplifica la confirmación del registro:

- Maneja automáticamente la creación de payload a partir de credenciales FIDO
- Maneja la llamada a la API internamente
- Devuelve `Bool` indicando éxito


**Ejemplo:**

```swift
extension ViewModel: FidoRegistrationCallback {
    func onSuccess(credential: PublicKeyCredential, response: AuthenticatorAttestationResponse) {
        // El SDK maneja la creación de payload automáticamente
        let success = sdk.confirmEnrollment(enrollmentId: enrollmentId, credential: credential, response: response)
        if success {
            // Registro confirmado
        }
    }
    
    func onError(error: String) {
        // Manejar error
    }
}
```

Para completar el proceso de registro, necesitarás enviar los valores que recibiste al siguiente endpoint:

```bash
POST /payments/br/enrollments/{enrollment_id}/confirm/
```

```json
// Cuerpo de la Solicitud
{
  "confirmation_data": {
    "authenticatorAttachment": "platform",
    "id": "{{encodedId}}",
    "rawId": "{{rawId}}",
    "type": "public-key",
    "response": {
      "attestationObject": "{{encodedAttestationObject}}",
      "clientDataJSON": "{{encodedClientDataJSON}}"
    }
  }
}
```

| Parámetro | Tipo | Descripción |
|  --- | --- | --- |
| `authenticatorAttachment` | string | El tipo de autenticador. Debe establecerse en `platform`. |
| `id` | string | El `encodedId` que recibiste del método `startRegistration()`. |
| `rawId` | string | El `rawId` que recibiste del método `startRegistration()`. |
| `type` | string | El tipo de credencial FIDO que se está generando. Debe establecerse en `public-key`. |
| `response.attestationObject` | string | El `encodedAttestationObject` que recibiste del método `startRegistration()`. |
| `response.clientDataJSON` | string | El `encodedClientDataJSON` que recibiste del método `startRegistration()`. |


Belvo responderá con un `204 - No Content` y enviará la información a la institución para completar el proceso de registro.

Consejos para Consultas
Envía una solicitud cada dos segundos hasta que recibas una respuesta o pasen dos minutos sin respuesta. Si no recibes respuesta después de dos minutos, muestra una pantalla de “Intenta de nuevo” a tu usuario y reinicia el proceso. En segundo plano, el registro pasará a `status` = `FAILED`.

Necesitarás consultar el siguiente endpoint hasta que recibas una respuesta de la API de Belvo. Una vez que recibas una respuesta, verifica el campo `status`.

```bash
GET /enrollments/{enrollment_id}/
```

Si el `status` es `SUCCEEDED`, ¡perfecto! El registro está listo y puedes comenzar a realizar pagos.

## Realizar un Pago

Una vez que el dispositivo de un usuario está registrado exitosamente, puedes iniciar solicitudes de pago utilizando sus credenciales biométricas almacenadas. Este proceso involucra:

1. Seleccionar un Registro
2. Crear una intención de pago
3. Recopilar datos de autenticación biométrica
4. Autorizar el pago


```mermaid
sequenceDiagram
    autonumber

    participant EndUser
    participant ClientAppBackend
    participant BiometricPixSDK
    participant Payments

    %% 1 - Creación de Intención de Pago usando registro autorizado
    Note over EndUser,Payments: 1. Usuario selecciona Registro (API)

    EndUser ->> ClientAppBackend: Hace clic en "Realizar Pago"
    ClientAppBackend ->> Payments: GET /enrollments/?device_id=1234
    Payments -->> ClientAppBackend: Devuelve lista de registros
    ClientAppBackend -->> EndUser: Muestra lista de registros
    EndUser ->> ClientAppBackend: Elige de la lista de registros

    Note over EndUser,Payments: 2. Crear Intención de Pago (API)

    ClientAppBackend ->> Payments: POST /payment-intents/ (enrollment_id)
    Payments -->> ClientAppBackend: Devuelve datos de payment_intent (id, fido_options)
    ClientAppBackend ->> ClientAppBackend: Persiste ID de Intención de Pago

    %% 2 - Autorización de Intención de Pago usando AttestationObject + RiskSignals
    Note over EndUser,Payments: 3. Recopilar datos biométricos (SDK)

    ClientAppBackend ->> BiometricPixSDK: startSigning(fidoOptions)
    ClientAppBackend ->> BiometricPixSDK: collectRiskSignals(accountTenure)
    BiometricPixSDK -->> ClientAppBackend: Devuelve credentialId, attestationObject, clientDataJSON, riskSignals

    Note over EndUser,Payments: 4. Autorizar pago (API)

    ClientAppBackend ->> Payments: POST /payment-intents/{id}/authorize/ (credentialId, attestationObject, clientDataJSON, riskSignals)
    Payments -->> ClientAppBackend: 204 - No Content
    ClientAppBackend ->> Payments: Poll GET /payment-intents/{id}/
    Payments -->> ClientAppBackend: status = SUCCEEDED

    ClientAppBackend ->> EndUser: Muestra pantalla de éxito
```

## **Seleccionar Inscripción (API)**

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `listEnrollments()` que simplifica la obtención de inscripciones:

- Maneja automáticamente la llamada a la API con el ID del dispositivo
- Devuelve `[Enrollment]` con datos enriquecidos de la institución
- Cada inscripción incluye opcionalmente el objeto completo `Institution`


**Ejemplo:**

```swift
let enrollments = sdk.listEnrollments(deviceId: deviceId)
enrollments.forEach { enrollment in
    if let institution = enrollment.institution {
        print("\(institution.displayName): \(enrollment.status)")
    }
}
```

Utiliza el método de la API Listar todas las inscripciones, con el parámetro de consulta requerido `device_id`, para solicitar todas las inscripciones que tu usuario ha realizado usando tu aplicación y su dispositivo actual. Muestra esta lista de inscripciones al usuario, permitiéndole elegir qué inscripción usar para el pago. Guarda el `id` de esa inscripción (utilizado en el siguiente paso Crear Intento de Pago).

```bash
GET /enrollments/?device_id={device_id}
```

## **Crear Payment Intent (API)**

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `createPaymentIntent()` que simplifica la creación de payment intents:

- Maneja la llamada a la API internamente
- Devuelve el objeto completo `PaymentIntent` con opciones FIDO
- Soporta todos los parámetros de payment intent


**Ejemplo:**

```swift
let payload = CreatePaymentIntentPayload(
    amount: 100.50,
    customer: Customer(identifier: "12345678900"),
    description: "Pago por servicios",
    allowedPaymentMethodTypes: ["open_finance_biometric_pix"],
    paymentMethodDetails: PaymentMethodDetails(
        openFinanceBiometricPix: OpenFinanceBiometricPixPaymentMethodDetails(
            beneficiaryBankAccount: "bank-account-id",
            enrollment: "enrollment-id"
        )
    )
)
let paymentIntent = sdk.createPaymentIntent(payload: payload)
```

Una vez que tengas la Enrollment seleccionada por el usuario, puedes crear un Payment Intent:

```shell
POST /payments/br/payment-intents/
```

```json
{
    "amount": 0.13,
    "allowed_payment_method_types": [
        "open_finance_biometric_pix"
    ],
    "customer": "{{customer.id}}",
    "description": "Test Payment Intent with Enrollment",
    "statement_description": "Descripción para mostrar en el estado de cuenta",
    "payment_method_details": {
        "open_finance_biometric_pix": {
            "beneficiary_bank_account": "{{bank_account.id}}",
            "enrollment": "{{enrollment.id}}"
        }
    },
    "confirm": true
}
```

| Parámetro | Tipo | Requerido | Descripción |
|  --- | --- | --- | --- |
| `amount` | número | si | El monto a pagar. |
| `allowed_payment_method_types` | string | si | El tipo de método de pago. Debe establecerse en `open_finance_biometric_pix`. |
| `customer` | string (uuid) | si | El `id` del cliente del cual estás solicitando pagos. |
| `description` | string | si | Tu descripción para el pago. |
| `statement_description` | string | si | La descripción que aparecerá en el estado de cuenta del usuario. |
| `payment_method_details.open_finance_biometric_pix.beneficiary_bank_account` | string (uuid) | si | El `id` de la cuenta bancaria que recibirá los fondos. |
| `payment_method_details.open_finance_biometric_pix.enrollment` | string (uuid) | si | El `id` de la Enrollment que el usuario seleccionó. |
| `confirm` | booleano | si | Confirma que el pago está listo para ser procesado. Debe establecerse en `true`. |


En la respuesta, Belvo devolverá el `payment_intent.id` y el objeto `fido_options` que son necesarios para el siguiente paso de autenticación biométrica. Necesitas:

- Persistir el `payment_intent.id` en tu backend.
- Guardar el `fido_options` en una variable para ser usado en el siguiente paso en el SDK de Belvo.


```json
{
  "id": "uuid", // [!code highlight]
  "status": "PENDING",
  "payment_method_information": {
	  "open_finance_biometric_pix": {
	      "provider": "belvo",
	      "consent_id": "urn:nubank:023230b9-1211-3420-bf6d-e7d56e87bdf1",
	      "fido_options": { // [!code highlight]
	          "rpId": "belvo.com",
	          "timeout": 300000,
	          "challenge": "oGW096Hvr8sVUIOf-10iqWI7ZfSx2GhoU359bBRK9h4",
	          "allowCredentials": [
	              {
	                  "id": "AfD-uI4LUzJAuzyLBRrPncocLusMgZ8yHNuuUl-7NSFbBlqrW2rMF0D_Ao-orNqdX3YZVf8_wk1jj--HuNH1uKE",
	                  "type": "public-key"
	              }
	          ]
	      },
	      "end_to_end_id": "E432158152025061315009OzwiMmDSO7",
	      "external_payment_id": "bde3bb4d-5b48-4875-b69d-7f2beee4fb42",
	      "provider_request_id": "afc99a8b-e0c7-4a8b-85d7-193bd70e4cc0"
	  }
	}
}
```

## Recopilar Datos Biométricos y Señales de Riesgo (SDK)

Usando las `fido_options` recibidas del intento de pago, inicia el proceso de autenticación biométrica utilizando el método `startSigning(fidoOptions)` del SDK de Belvo para iOS. Después de que el usuario se autentique, también necesitarás llamar a `collectRiskSignals(accountTenure)` para recopilar información del dispositivo.

Los resultados de estos métodos contienen los valores que necesitarás enviar a tu backend para autorizar el pago.

```swift
import Foundation
import BiometricPixSDK

class FidoAuthenticationViewModel : NSObject, ObservableObject {
    private let sdk = BiometricPixSDK()

    func startSigning(fidoOptions: String) {
        do {
            // Nota: El método para iniciar la autenticación de pago es startSigning.
            sdk.startSigning(
                fidoResponseString: fidoOptions,// cadena json solicitada desde la API del backend
                fallbackCredential: nil,//cadena de credenciales de respaldo si está disponible
                callback: self// instancia de callback
            )
        } catch {
                        // Manejo de errores
        }
    }
    
    private func collectRiskSignals() {
        do {
            // Recopilar señales de riesgo con la fecha de creación del usuario
            let signals = sdk.collectRiskSignals(
                accountTenure: "YYYY-MM-DD"
            )
            // Envía las señales a tu backend para ser utilizadas en el paso de autorización.
        } catch {
            // manejar error
        }
    }
}

// implementando callback para autenticación
extension FidoAuthenticationViewModel: FidoAuthenticationCallback {
    func onError(error: String) {
                // Manejar errores de autenticación
    }

    func onSuccess(response assertionResponse: AssertionResponse) {
                // Manejar autenticación exitosa
        // Extraer datos de assertionResponse y enviar a tu backend.
        // Luego, llama a collectRiskSignals.
        collectRiskSignals()
    }
}
```

Al usar este modelo de vista en vistas de SwiftUI, decláralos como propiedades @ObservedObject para asegurar que no sean destruidos durante las re-renderizaciones de la vista. Esto es crítico para que los callbacks funcionen correctamente.

```swift
import SwiftUI

struct MyView: View {
    @ObservedObject var registrationViewModel = FidoRegistrationViewModel()
// ...
}
```

## Autorizar Pago (API)

Método de Conveniencia del SDK Disponible
El SDK de iOS proporciona un método `authorizePaymentIntent()` que simplifica la autorización de pagos:

- Maneja la llamada a la API internamente
- Acepta `AuthorizePaymentIntentPayload` con plataforma, señales de riesgo y aserción
- Devuelve `Bool` indicando éxito


**Ejemplo:**

```swift
let payload = AuthorizePaymentIntentPayload(
    platform: "ios",
    riskSignals: riskSignals,
    assertion: assertion
)
let success = sdk.authorizePaymentIntent(paymentIntentId: paymentIntentId, payload: payload)
```

Después de obtener toda la información requerida en el paso de Recolección de Datos Biométricos y Señales de Riesgo (SDK), ahora puedes autorizar el pago usando la API de Belvo.

```shell
POST /payment-intents/{payment_intent_id}/authorize/
```

- Belvo procesará la autorización. Necesitarás hacer sondeos a `GET /payment-intents/{id}/` hasta que el `status` de la intención de pago se convierta en `SUCCEEDED`.
**Estrategia de Sondeo:** Similar a la inscripción, recomendamos sondear el estado de la intención de pago (`GET /payment-intents/{payment_intent_id}/`) cada dos segundos por hasta dos minutos hasta que el estado sea `SUCCEEDED`. Si el estado no cambia o ocurre un error, informa al usuario y sugiere reintentar.
- Una vez que el pago sea exitoso, muestra una pantalla de confirmación al Usuario Final.


```json
// Ejemplo de Cuerpo de Solicitud POST /payment-intents/{id}/authorize/
{
  "risk_signals": {}, // El objeto de Señales de Riesgo recolectado
  "assertion": {
    "authenticatorAttachment": "platform",
    "id": "{{encodedId}}",
    "rawId": "{{rawId}}",
    "response": {
      "authenticatorData": "{{encodedAuthenticatorData}}",
      "clientDataJSON": "{{encodedClientDataJSON}}",
      "signature": "{{encodedSignature}}",
      "userHandle": "{{userHandle}}"
      
    },
    "type": "public-key"
  }
}
```

La API de Belvo devolverá un `204 - Not Content`. Después de esto, necesitas sondear el siguiente endpoint para obtener el estado final del pago:

```shell
GET /payment-intents/{payment_intent_id}/
```

Consejos de Sondeo
Envía una solicitud cada dos segundos hasta que recibas una respuesta o pasen dos minutos sin respuesta. Si no recibes respuesta después de dos minutos, muestra una pantalla de “Intenta de nuevo” a tu usuario y reinicia el proceso. En segundo plano, la Intención de Pago y el Cargo asociado pasarán al `status` = `FAILED`.