# Guía de Pix Biometria (Android SDK - Integración Simplificada) 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. 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. Esta guía demuestra la integración utilizando los métodos de conveniencia del SDK de Android de Belvo. El SDK maneja la comunicación de backend, los flujos de OAuth y el registro FIDO internamente, proporcionando un camino de integración simplificado. El primer paso para habilitar la recolección de pagos biométricos es **registrar** el dispositivo del usuario con su institución. Durante el registro, 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 el registro esté completo, puedes comenzar a solicitar pagos directamente desde el dispositivo del usuario. ## Prerrequisitos 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 Android SDK** ### 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 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:** - Android API Level 24 (Android 7.0) o superior - Kotlin 1.9.0 o superior **Agrega a tu `build.gradle.kts` (nivel de Módulo):** ```kotlin dependencies { implementation("com.belvo:biometric-pix-core:1.0.0") } ``` **Sincroniza tu proyecto** ¡y estarás listo para comenzar! ### Configuración de la App **Agrega permisos a `AndroidManifest.xml`:** ```xml ``` **Agrega soporte de App Links para callbacks de OAuth:** ```xml ``` **Comparte el nombre de tu paquete y la huella digital del certificado SHA-256 con Belvo:** ```bash # Obtén tu huella digital SHA-256 keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android # Formato para compartir con Belvo: # Package: com.yourcompany.appname # SHA-256: AA:BB:CC:DD:EE:FF:... ``` ## Permisos e Inicialización del SDK Momento de Solicitud de Permisos Los permisos **deben** ser solicitados antes de la inicialización del SDK. Además, la solicitud de permisos solo puede ser llamada desde un contexto de Activity. **Paso 1: Solicitar Permisos Primero** ```kotlin import com.belvo.biometricpixsdk.BiometricPixSDK import androidx.activity.ComponentActivity class EnrollmentActivity : ComponentActivity() { private lateinit var sdk: BiometricPixSDK override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // DEBE solicitar permisos ANTES de inicializar el SDK requestPermissions() } private fun requestPermissions() { BiometricPixSDK.requestPermission(this) { granted -> if (granted) { // Permisos concedidos, ahora inicializar el SDK initializeSDK() } else { // Manejar la denegación de permisos showError("Se requiere permiso de ubicación para el registro") } } } private fun initializeSDK() { // Inicializar DESPUÉS de que se concedan los permisos sdk = BiometricPixSDK( context = this, accessToken = getAccessToken() // Desde tu backend ) // Ahora listo para proceder con el registro } override fun onDestroy() { super.onDestroy() if (::sdk.isInitialized) { sdk.cleanup() } } } ``` Gestión de Recursos Siempre llama a `cleanup()` cuando hayas terminado con el SDK (por ejemplo, cuando la actividad se destruye o el usuario cierra sesión) para liberar adecuadamente los recursos y limpiar las tareas en segundo plano. ## Flujo de Inscripción (6 Pasos) El proceso de inscripción registra el dispositivo de un usuario con su institución para pagos biométricos. ```mermaid sequenceDiagram autonumber participant Usuario participant TuApp participant BiometricPixSDK participant BelvoAPI participant Institución Note over TuApp,BiometricPixSDK: Llamada 1: getPaymentInstitutions() Usuario->>TuApp: Inicia inscripción TuApp->>BiometricPixSDK: getPaymentInstitutions() BiometricPixSDK->>BelvoAPI: Obtener instituciones BelvoAPI-->>BiometricPixSDK: Lista de instituciones BiometricPixSDK-->>TuApp: List<Institution> TuApp->>Usuario: Mostrar selector de institución Usuario-->>TuApp: Selecciona institución Note over TuApp,BiometricPixSDK: Llamada 2: createEnrollment() + openRedirectUrl() TuApp->>BiometricPixSDK: createEnrollment(cpf, institution, accountTenure, callbackUrl) BiometricPixSDK->>BiometricPixSDK: Recopilar señales de riesgo internamente BiometricPixSDK->>BelvoAPI: POST /enrollments/ BelvoAPI-->>BiometricPixSDK: Inscripción creada (redirect_url) BiometricPixSDK-->>TuApp: Objeto de inscripción TuApp->>BiometricPixSDK: openRedirectUrl(context, redirect_url) BiometricPixSDK->>Institución: Abrir aplicación de la institución Usuario->>Institución: Aprobar inscripción en la aplicación de la institución Institución-->>TuApp: Callback OAuth (code, state, id_token) Note over TuApp,BiometricPixSDK: Llamada 3: completeEnrollmentAfterRedirection() TuApp->>BiometricPixSDK: completeEnrollmentAfterRedirection(callbackUrl) BiometricPixSDK->>BelvoAPI: POST /enrollments/complete-redirection/ BelvoAPI-->>BiometricPixSDK: Inscripción actualizada BiometricPixSDK-->>TuApp: Objeto de inscripción Note over TuApp,BiometricPixSDK: Llamada 4: getFidoRegistrationOptions() TuApp->>BiometricPixSDK: getFidoRegistrationOptions(enrollmentId) BiometricPixSDK->>BelvoAPI: Consultar opciones FIDO (reintento automático) BelvoAPI-->>BiometricPixSDK: Opciones de registro FIDO BiometricPixSDK-->>TuApp: FidoRegistrationOptions Note over TuApp,BiometricPixSDK: Llamada 5: startRegistration() TuApp->>BiometricPixSDK: startRegistration(fidoOptions, callback) BiometricPixSDK->>Usuario: Solicitar biometría (huella digital/rostro) Usuario-->>BiometricPixSDK: Proporciona biometría BiometricPixSDK-->>TuApp: Credencial vía callback Note over TuApp,BiometricPixSDK: Llamada 6: confirmEnrollment() TuApp->>BiometricPixSDK: confirmEnrollment(enrollmentId, credential) BiometricPixSDK->>BelvoAPI: POST /enrollments/{id}/confirm/ BelvoAPI->>Institución: Registrar credencial FIDO Institución-->>BelvoAPI: Registro confirmado BelvoAPI-->>BiometricPixSDK: Inscripción EXITOSA BiometricPixSDK-->>TuApp: Éxito (Boolean) TuApp->>Usuario: Mostrar pantalla de éxito ``` ### Paso 1: Obtener Instituciones de Pago Obtén la lista de instituciones que soportan pagos biométricos: ```kotlin import com.belvo.biometricpixsdk.BiometricPixSDK import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch class EnrollmentViewModel( private val sdk: BiometricPixSDK ) : ViewModel() { private val _institutions = MutableStateFlow>(emptyList()) val institutions: StateFlow> = _institutions fun loadInstitutions() { viewModelScope.launch { try { _institutions.value = sdk.getPaymentInstitutions() } catch (e: Exception) { // Manejar error (red, autenticación, etc.) _error.value = "Error al cargar instituciones: ${e.message}" } } } } ``` **Mostrar instituciones al usuario:** ```kotlin @Composable fun InstitutionPickerScreen( viewModel: EnrollmentViewModel ) { val institutions by viewModel.institutions.collectAsState() LazyColumn { items(institutions) { institution -> InstitutionItem( institution = institution, onClick = { viewModel.selectInstitution(institution) } ) } } LaunchedEffect(Unit) { viewModel.loadInstitutions() } } @Composable fun InstitutionItem( institution: Institution, onClick: () -> Unit ) { Row( modifier = Modifier .fillMaxWidth() .clickable(onClick = onClick) .padding(16.dp) ) { AsyncImage( model = institution.iconLogo, contentDescription = institution.displayName, modifier = Modifier.size(40.dp) ) Spacer(modifier = Modifier.width(16.dp)) Text(text = institution.displayName) } } ``` ### Paso 2: Crear Inscripción y Abrir la Aplicación de la Institución Crea la inscripción e inmediatamente abre la aplicación de la institución: ```kotlin fun startEnrollment() { val institution = _selectedInstitution.value ?: return viewModelScope.launch { try { // Crear inscripción val enrollment = sdk.createEnrollment( cpf = userCPF, // CPF del usuario institution = institution.id, // ID de la institución seleccionada accountTenure = customerCreatedDate, // Formato "YYYY-MM-DD" callbackUrl = "https://yourdomain.com/callback" ) // Guardar ID de inscripción e ID de dispositivo para más tarde _enrollmentId.value = enrollment.id _deviceId.value = enrollment.details.riskSignals.deviceId // Inmediatamente abrir la aplicación de la institución usando la URL de redirección enrollment.details.redirectUrl?.let { url -> sdk.openRedirectUrl(context, url) } ?: run { _error.value = "No se recibió URL de redirección de la inscripción" } } catch (e: Exception) { _error.value = "La creación de la inscripción falló: ${e.message}" } } } ``` Formato de Antigüedad de Cuenta El parámetro `accountTenure` debe ser la fecha en que el usuario fue creado como Cliente de Belvo, en formato `YYYY-MM-DD`. Extrae esto del timestamp `created_at` del Cliente (primeros 10 caracteres). El método `openRedirectUrl()` del SDK maneja la apertura de la aplicación de la institución automáticamente. La institución redirigirá de vuelta a tu `callbackUrl` con parámetros OAuth. ### Paso 5: Completar el Registro Después de la Redirección Maneja el callback de OAuth en tu actividad y completa el registro: ```kotlin // En tu MainActivity override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) intent?.data?.let { uri -> handleEnrollmentCallback(uri) } } fun handleEnrollmentCallback(uri: Uri) { viewModelScope.launch { try { val enrollment = sdk.completeEnrollmentAfterRedirection( callbackUrl = uri.toString() // SDK analiza los parámetros automáticamente ) // Verifica si fue exitoso when (enrollment.status) { "PENDING" -> { // Éxito - procede al registro FIDO getFidoOptions(enrollment.id) } "FAILED" -> { // Maneja el fallo _error.value = "${enrollment.statusReasonCode}: ${enrollment.statusReasonMessage}" } } } catch (e: Exception) { _error.value = "Error al completar el registro: ${e.message}" } } } ``` Alternativa: Parámetros Manuales Si prefieres analizar la URL de callback tú mismo, puedes pasar los parámetros individualmente: ```kotlin val enrollment = sdk.completeEnrollmentAfterRedirection( state = stateParam, code = codeParam, idToken = idTokenParam ) ``` ### Paso 4: Obtener Opciones de Registro FIDO Recupera las opciones FIDO necesarias para el registro biométrico. El SDK realiza automáticamente la consulta durante hasta 5 minutos: ```kotlin fun getFidoOptions(enrollmentId: String) { viewModelScope.launch { // El SDK consulta automáticamente cada 1 segundo durante hasta 5 minutos val fidoOptions = sdk.getFidoRegistrationOptions(enrollmentId) if (fidoOptions != null) { // Opciones FIDO recibidas, proceder al registro biométrico startBiometricRegistration(fidoOptions) } else { // El tiempo de espera de la consulta se agotó (pasaron 5 minutos) _error.value = "Tiempo de espera agotado para las opciones FIDO. Por favor, inténtalo de nuevo." } } } ``` Consulta Automática El método `getFidoRegistrationOptions()` maneja toda la lógica de consulta automáticamente. Verifica cada 1 segundo durante hasta 5 minutos, por lo que no necesitas implementar ninguna lógica de reintento. ### Paso 5: Registrar Biometría y Confirmar Solicite al usuario los datos biométricos y confirme la inscripción: ```kotlin class EnrollmentViewModel( private val sdk: BiometricPixSDK ) : ViewModel() { private var enrollmentId: String? = null fun startBiometricRegistration(fidoOptions: FidoRegistrationOptions) { try { sdk.startRegistration( fidoOptions = fidoOptions.toJsonString(), callback = object : FidoRegistrationCallback { override fun onSuccess(credential: PublicKeyCredential, response: AuthenticatorAttestationResponse) { // SDK maneja la creación de payload automáticamente confirmEnrollment(credential, response) } override fun onError(error: String) { _error.value = "El registro biométrico falló: $error" } } ) } catch (e: Exception) { _error.value = "Error al iniciar el registro: ${e.message}" } } private fun confirmEnrollment( credential: PublicKeyCredential, response: AuthenticatorAttestationResponse ) { val enrollmentId = this.enrollmentId ?: return viewModelScope.launch { val success = sdk.confirmEnrollment( enrollmentId = enrollmentId, credential = credential, response = response ) if (success) { _state.value = EnrollmentState.Success } else { _error.value = "La confirmación de inscripción falló" } } } } ``` ¡Inscripción Completa! El dispositivo ahora está inscrito y listo para pagos biométricos. ## Flujo de Pago (4 Pasos) Una vez inscrito, iniciar pagos requiere cuatro llamadas a métodos: ```mermaid sequenceDiagram autonumber participant Usuario participant TuApp participant BiometricPixSDK participant BelvoAPI participant Institución Note over TuApp,BiometricPixSDK: Llamada 1: listEnrollments() Usuario->>TuApp: Inicia pago TuApp->>BiometricPixSDK: listEnrollments(deviceId) BiometricPixSDK->>BelvoAPI: GET /enrollments/?device_id=... BelvoAPI-->>BiometricPixSDK: List<Enrollment> BiometricPixSDK-->>TuApp: Lista de inscripciones TuApp->>Usuario: Mostrar selector de inscripción Usuario-->>TuApp: Selecciona inscripción Note over TuApp,BiometricPixSDK: Llamada 2: createPaymentIntent() TuApp->>BiometricPixSDK: createPaymentIntent(payload) BiometricPixSDK->>BelvoAPI: POST /payment-intents/ BelvoAPI-->>BiometricPixSDK: PaymentIntent (con opciones FIDO) BiometricPixSDK-->>TuApp: Objeto PaymentIntent Note over TuApp,BiometricPixSDK: Llamada 3: startSigning() + collectRiskSignals() TuApp->>BiometricPixSDK: startSigning(fidoOptions, callback) BiometricPixSDK->>Usuario: Solicitar biometría (huella/rostro) Usuario-->>BiometricPixSDK: Proporciona biometría BiometricPixSDK-->>TuApp: Afirmación vía callback TuApp->>BiometricPixSDK: collectRiskSignals(accountTenure) BiometricPixSDK-->>TuApp: RiskSignals Note over TuApp,BiometricPixSDK: Llamada 4: authorizePaymentIntent() TuApp->>BiometricPixSDK: authorizePaymentIntent(paymentIntentId, payload) BiometricPixSDK->>BelvoAPI: POST /payment-intents/{id}/authorize/ BelvoAPI->>Institución: Procesar pago Institución-->>BelvoAPI: Pago confirmado BelvoAPI-->>BiometricPixSDK: Pago SUCCEEDED BiometricPixSDK-->>TuApp: Autorización exitosa (Boolean) TuApp->>Usuario: Mostrar confirmación de pago ``` ### Paso 1: Listar Inscripciones Obtén todas las inscripciones para el dispositivo actual y permite que el usuario seleccione una: ```kotlin class PaymentViewModel( private val sdk: BiometricPixSDK ) : ViewModel() { private val _enrollments = MutableStateFlow>(emptyList()) val enrollments: StateFlow> = _enrollments fun loadEnrollments(deviceId: String) { viewModelScope.launch { try { _enrollments.value = sdk.listEnrollments(deviceId) } catch (e: Exception) { _error.value = "Failed to load enrollments: ${e.message}" } } } } ``` **Mostrar inscripciones al usuario:** ```kotlin @Composable fun EnrollmentSelectionScreen( viewModel: PaymentViewModel ) { val enrollments by viewModel.enrollments.collectAsState() LazyColumn { items(enrollments) { enrollment -> enrollment.institution?.let { institution -> EnrollmentItem( enrollment = enrollment, institution = institution, onClick = { viewModel.selectEnrollment(enrollment) } ) } } } LaunchedEffect(Unit) { viewModel.loadEnrollments(savedDeviceId) } } @Composable fun EnrollmentItem( enrollment: Enrollment, institution: Institution, onClick: () -> Unit ) { Row( modifier = Modifier .fillMaxWidth() .clickable(onClick = onClick) .padding(16.dp) ) { AsyncImage( model = institution.iconLogo, contentDescription = institution.displayName, modifier = Modifier.size(40.dp) ) Spacer(modifier = Modifier.width(16.dp)) Column { Text(text = institution.displayName) Text( text = "Estado: ${enrollment.status}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } } ``` ### Paso 2: Crear una Intención de Pago Crea una intención de pago con todos los detalles del pago: ```kotlin fun createPayment( amount: Double, enrollmentId: String, beneficiaryAccountId: String ) { val payload = CreatePaymentIntentPayload( amount = amount, customer = Customer(identifier = userCPF), // CPF del usuario description = "Pago por servicios", statementDescription = "Compra ACME Corp", allowedPaymentMethodTypes = listOf("open_finance_biometric_pix"), paymentMethodDetails = PaymentMethodDetails( openFinanceBiometricPix = OpenFinanceBiometricPixPaymentMethodDetails( beneficiaryBankAccount = beneficiaryAccountId, enrollment = enrollmentId ) ), confirm = true ) viewModelScope.launch { try { val paymentIntent = sdk.createPaymentIntent(payload) // Guardar ID de la intención de pago _paymentIntentId.value = paymentIntent.id // Extraer opciones FIDO para el siguiente paso paymentIntent.paymentMethodInformation?.openFinanceBiometricPix?.fidoOptions?.let { fidoOptions -> promptForBiometric(fidoOptions) } } catch (e: Exception) { _error.value = "Error al crear la intención de pago: ${e.message}" } } } ``` ### Paso 3: Recopilar Señales Biométricas y de Riesgo Solicitar autenticación biométrica y recopilar señales de riesgo: ```kotlin class PaymentViewModel( private val sdk: BiometricPixSDK ) : ViewModel() { private var paymentIntentId: String? = null private var riskSignals: RiskSignals? = null private var assertionResponse: AssertionResponse? = null fun promptForBiometric(fidoOptions: FidoOptions) { try { sdk.startSigning( fidoOptions = fidoOptions.toJsonString(), fallbackCredential = null, // Opcional: proporcionar si tienes uno callback = object : FidoAuthenticationCallback { override fun onSuccess(response: AssertionResponse) { // Almacenar respuesta de aserción assertionResponse = response // Recopilar señales de riesgo collectRiskSignals() } override fun onError(error: String) { _error.value = "La autenticación biométrica falló: $error" } } ) } catch (e: Exception) { _error.value = "Error al iniciar la firma: ${e.message}" } } private fun collectRiskSignals() { try { riskSignals = sdk.collectRiskSignals( accountTenure = customerCreatedDate // "YYYY-MM-DD" ) // Una vez que tenemos tanto la aserción como las señales de riesgo, autorizar el pago if (assertionResponse != null && riskSignals != null) { authorizePayment() } } catch (e: Exception) { _error.value = "Error al recopilar señales de riesgo: ${e.message}" } } } ``` ### Paso 4: Autorizar Pago Autoriza el pago con los datos recopilados: ```kotlin private fun authorizePayment() { val paymentIntentId = this.paymentIntentId ?: return val riskSignals = this.riskSignals ?: return val assertion = this.assertionResponse ?: return val payload = AuthorizePaymentIntentPayload( platform = "android", riskSignals = riskSignals, assertion = assertion ) viewModelScope.launch { val success = sdk.authorizePaymentIntent( paymentIntentId = paymentIntentId, payload = payload ) if (success) { _state.value = PaymentState.Success } else { _error.value = "Payment authorization failed" } } } ``` ¡Flujo de Pago Completo! El pago ahora está autorizado y en proceso. Necesitas monitorear eventos de webhook para rastrear su estado final. ## Manejo de Errores Todos los métodos del SDK que realizan operaciones de red pueden lanzar excepciones. Asegúrate de manejarlas adecuadamente: ```kotlin try { val institutions = sdk.getPaymentInstitutions() // Éxito } catch (e: BiometricPixSDKException) { when (e) { is BiometricPixSDKException.NetworkError -> { // Manejar problemas de red Log.e(TAG, "Error de red: ${e.message}") } is BiometricPixSDKException.AuthenticationError -> { // Manejar token inválido o expirado Log.e(TAG, "Autenticación fallida - el token puede estar expirado") } is BiometricPixSDKException.InvalidParametersError -> { // Manejar entrada inválida Log.e(TAG, "Parámetros inválidos: ${e.message}") } is BiometricPixSDKException.UnknownError -> { // Manejar errores desconocidos Log.e(TAG, "Error: ${e.message}") } } } catch (e: Exception) { Log.e(TAG, "Error inesperado: ${e.message}") } ``` ## Webhooks Aunque el SDK maneja la mayor parte del flujo de trabajo, aún debes escuchar las notificaciones de webhook para manejar actualizaciones asíncronas: - **Cambios en el estado de inscripción:** tipo de webhook `ENROLLMENTS` - **Cambios en el estado de pago:** tipo de webhook `PAYMENT_INTENTS` Para obtener la documentación completa de los webhooks, consulta Webhooks de Pagos (Brasil). ## Referencia de Métodos del SDK ### Inicialización **`BiometricPixSDK(context: Context, accessToken: String)`** - Crea una nueva instancia del SDK con el contexto y el access token proporcionados - Debe inicializarse una vez y reutilizarse en toda tu aplicación - Access token obtenido del endpoint `/payments/api/widget-token/` **`cleanup()`** - Libera los recursos del SDK y limpia las tareas en segundo plano - Llamar en `onCleared()` o cuando el usuario cierra sesión ### Métodos de Inscripción **`getPaymentInstitutions(): List`** - Obtiene todas las instituciones que admiten pagos biométricos - Devuelve una lista de objetos `Institution` con `id`, `displayName`, `iconLogo`, etc. - Lanza una excepción en caso de errores de red o autenticación **`createEnrollment(cpf: String, institution: String, accountTenure: String, callbackUrl: String): Enrollment`** - Crea la inscripción y recopila señales de riesgo automáticamente - `cpf`: Número de CPF del usuario - `institution`: ID de la institución de `getPaymentInstitutions()` - `accountTenure`: Fecha de creación del cliente en formato "YYYY-MM-DD" - `callbackUrl`: Enlace profundo para la devolución de llamada OAuth (debe estar registrado como App Link) - Devuelve un objeto `Enrollment` con `id`, `redirect_url`, `device_id` **`openRedirectUrl(context: Context, url: String)`** - Abre la aplicación de la institución usando la URL de redirección proporcionada - Maneja la redirección automáticamente, incluyendo el enlace profundo - Debe ser llamado inmediatamente después de `createEnrollment()` con el `redirect_url` de la respuesta de inscripción - `context`: Contexto de la Actividad o Aplicación - `url`: La URL de redirección del objeto de inscripción **`completeEnrollmentAfterRedirection(callbackUrl: String): Enrollment`** - Completa la inscripción después de la devolución de llamada OAuth de la institución - Analiza automáticamente los parámetros OAuth de la URL completa de devolución de llamada - Alternativa: `completeEnrollmentAfterRedirection(state: String, code: String, idToken: String)` **`getFidoRegistrationOptions(enrollmentId: String): FidoRegistrationOptions?`** - Consulta las opciones de registro FIDO (reintento automático: intervalo de 1 segundo, tiempo de espera de 5 minutos) - Devuelve `FidoRegistrationOptions` cuando está listo - Devuelve `null` si el tiempo de espera de la consulta se agota **`startRegistration(fidoOptions: String, callback: FidoRegistrationCallback)`** - Inicia el flujo de registro biométrico (reconocimiento de huella digital/rostro) - `fidoOptions`: Cadena JSON de `FidoRegistrationOptions.toJsonString()` - `callback`: Interfaz para recibir devoluciones de llamada de éxito/error **`confirmEnrollment(enrollmentId: String, credential: PublicKeyCredential, response: AuthenticatorAttestationResponse): Boolean`** - Confirma la inscripción con la credencial FIDO - Devuelve `true` en caso de éxito, `false` en caso de fallo ### Métodos de Pago **`listEnrollments(deviceId: String): List`** - Obtiene todas las inscripciones para un dispositivo - Devuelve una lista de objetos `Enrollment` con datos enriquecidos de la institución - Filtrar por `status == "SUCCEEDED"` para mostrar solo inscripciones activas **`createPaymentIntent(payload: CreatePaymentIntentPayload): PaymentIntent`** - Crea una intención de pago - Devuelve `PaymentIntent` con `id` y `paymentMethodInformation.openFinanceBiometricPix.fidoOptions` **`startSigning(fidoOptions: String, fallbackCredential: String?, callback: FidoAuthenticationCallback)`** - Inicia la autenticación biométrica para el pago - `fallbackCredential`: Credencial opcional para escenarios de reintento - `callback`: Interfaz para recibir la respuesta de la afirmación **`collectRiskSignals(accountTenure: String): RiskSignals`** - Recoge huellas digitales del dispositivo y señales de seguridad - `accountTenure`: Fecha de creación del cliente en formato "YYYY-MM-DD" - Devuelve un objeto `RiskSignals` para la carga útil de autorización **`authorizePaymentIntent(paymentIntentId: String, payload: AuthorizePaymentIntentPayload): Boolean`** - Autoriza el pago con afirmación biométrica y señales de riesgo - Devuelve `true` en caso de éxito, `false` en caso de fallo