# Guia de Pagamento por Biometria (Integração Apenas com iOS SDK)

Próximo Lançamento
Esta documentação cobre funcionalidades do nosso próximo lançamento. Embora a funcionalidade principal e o fluxo de trabalho descritos aqui permaneçam inalterados, você pode notar algumas refinamentos antes do lançamento final.

Com o Pagamento por Biometria da Belvo, a coleta de pagamentos dos usuários torna-se simples, eliminando a necessidade de os usuários navegarem até sua instituição financeira para aprovar cada solicitação de pagamento individual.

Este guia demonstra a integração usando os métodos de conveniência do Belvo iOS SDK. O SDK lida com a comunicação de backend, fluxos OAuth e registro FIDO internamente, proporcionando um caminho de integração simplificado.

O primeiro passo para habilitar a coleta de pagamentos biométricos é **registrar** o dispositivo do usuário com sua instituição. Durante o registro, dados chave sobre o dispositivo e as credenciais de chave pública do usuário são registrados de forma segura com sua instituição, garantindo que pagamentos futuros possam ser confirmados usando apenas autenticação biométrica.

Uma vez que o registro esteja completo, você pode começar a solicitar pagamentos diretamente do dispositivo do usuário.

## Pré-requisitos

Antes de começar, certifique-se de que você tenha:

1. **Gerado suas Chaves de API do Belvo Payments**
2. **Configurado Webhooks** para receber atualizações de status de pagamento e inscrição
3. **Gerado um Token de Acesso SDK** (veja abaixo)
4. **Instalado o SDK iOS da Belvo**


### Token de Acesso do SDK

Autenticação do SDK
O SDK de pagamentos biométricos requer um token de acesso para autenticar as solicitações da API. Gere este token a partir do seu servidor backend e passe-o para o SDK durante a inicialização.

Gere um token de acesso do SDK a partir do seu 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..."
}
```

Melhores Práticas para Tokens
Nunca codifique tokens diretamente no seu aplicativo. Sempre os gere no lado do servidor e implemente lógica segura de armazenamento e atualização.

### Instalação do SDK

**Requisitos Mínimos:**

- iOS 15.0 ou superior
- Swift 5.0 ou superior


**Instalação via Swift Package Manager:**

1. No Xcode, selecione **File** → **Add Packages...**
2. Insira: `https://github.com/belvo-finance-opensource/biometric-pix-ios-sdk`
3. Selecione os requisitos de versão e clique em **Add Package**
4. Escolha o produto **BiometricPixSDK** e clique em **Add Package**


### Configuração do App

**Adicione permissões ao seu arquivo `.entitlements`:**


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

**Adicione a descrição de uso de localização ao `Info.plist`:**


```xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>Este app usa localização para fins de segurança e prevenção de fraude.</string>
```

**Compartilhe seu Team ID e Bundle Identifier com a Belvo:**


```
Formato: TEAM_ID.BUNDLE_ID
Exemplo: ABCDEFGHIJ.com.yourcompany.appname
```

## Inicialização do SDK

Inicialize o SDK uma vez em seu aplicativo, normalmente em seu view model ou camada de serviço:


```swift
import BiometricPixSDK

class BiometricPixService {
    private let sdk: BiometricPixSDK
    
    init(accessToken: String) {
        self.sdk = BiometricPixSDK(accessToken: accessToken)
    }
    
    deinit {
        sdk.cleanup()
    }
}
```

Gerenciamento de Recursos
Sempre chame `cleanup()` quando terminar de usar o SDK (por exemplo, em `deinit` ou ao fazer logout) para liberar os recursos adequadamente.

## Fluxo de Cadastro (7 Etapas)

O processo de cadastro registra o dispositivo de um usuário com sua instituição para pagamentos biométricos.


```mermaid
sequenceDiagram
    autonumber

    participant User
    participant YourApp
    participant BiometricPixSDK
    participant BelvoAPI
    participant Institution
    
    Note over YourApp,BiometricPixSDK: Chamada 1: getPaymentInstitutions()
    User->>YourApp: Inicia o cadastro
    YourApp->>BiometricPixSDK: getPaymentInstitutions()
    BiometricPixSDK->>BelvoAPI: Buscar instituições
    BelvoAPI-->>BiometricPixSDK: Lista de instituições
    BiometricPixSDK-->>YourApp: [Institution]
    YourApp->>User: Exibir seletor de instituição
    User-->>YourApp: Seleciona instituição
    
    Note over YourApp,BiometricPixSDK: Chamada 2: requestPermission()
    YourApp->>BiometricPixSDK: requestPermission()
    BiometricPixSDK->>User: Solicitar permissão de localização
    User-->>BiometricPixSDK: Concede permissão
    BiometricPixSDK-->>YourApp: Permissão concedida
    
    Note over YourApp,BiometricPixSDK: Chamada 3: createEnrollment()
    YourApp->>BiometricPixSDK: createEnrollment(cpf, institution, accountTenure, callbackUrl)
    BiometricPixSDK->>BiometricPixSDK: Coletar sinais de risco internamente
    BiometricPixSDK->>BelvoAPI: POST /enrollments/
    BelvoAPI-->>BiometricPixSDK: Cadastro criado (redirect_url)
    BiometricPixSDK-->>YourApp: Objeto de cadastro
    
    Note over YourApp,Institution: Redirecionar para a Instituição
    YourApp->>User: Redirecionar para a instituição (redirect_url)
    User->>Institution: Aprovar cadastro no app da instituição
    Institution-->>YourApp: Callback OAuth (code, state, id_token)
    
    Note over YourApp,BiometricPixSDK: Chamada 4: completeEnrollmentAfterRedirection()
    YourApp->>BiometricPixSDK: completeEnrollmentAfterRedirection(callbackUrl)
    BiometricPixSDK->>BelvoAPI: POST /enrollments/complete-redirection/
    BelvoAPI-->>BiometricPixSDK: Cadastro atualizado
    BiometricPixSDK-->>YourApp: Objeto de cadastro
    
    Note over YourApp,BiometricPixSDK: Chamada 5: getFidoRegistrationOptions()
    YourApp->>BiometricPixSDK: getFidoRegistrationOptions(enrollmentId)
    BiometricPixSDK->>BelvoAPI: Consultar opções FIDO (auto-retry)
    BelvoAPI-->>BiometricPixSDK: Opções de registro FIDO
    BiometricPixSDK-->>YourApp: FidoRegistrationOptions
    
    Note over YourApp,BiometricPixSDK: Chamada 6: startRegistration()
    YourApp->>BiometricPixSDK: startRegistration(fidoOptions, callback)
    BiometricPixSDK->>User: Solicitar biometria (Face ID/Touch ID)
    User-->>BiometricPixSDK: Fornece biometria
    BiometricPixSDK-->>YourApp: Credencial via callback
    
    Note over YourApp,BiometricPixSDK: Chamada 7: confirmEnrollment()
    YourApp->>BiometricPixSDK: confirmEnrollment(enrollmentId, credential)
    BiometricPixSDK->>BelvoAPI: POST /enrollments/{id}/confirm/
    BelvoAPI->>Institution: Registrar credencial FIDO
    Institution-->>BelvoAPI: Registro confirmado
    BelvoAPI-->>BiometricPixSDK: Cadastro SUCEDIDO
    BiometricPixSDK-->>YourApp: Sucesso (Boolean)
    YourApp->>User: Mostrar tela de sucesso
```

### Passo 1: Obter Instituições de Pagamento

Busque a lista de instituições que suportam pagamentos biométricos:


```swift
import BiometricPixSDK

class EnrollmentViewModel: ObservableObject {
    private let sdk: BiometricPixSDK
    @Published var institutions: [Institution] = []
    @Published var selectedInstitution: Institution?
    
    init(sdk: BiometricPixSDK) {
        self.sdk = sdk
    }
    
    func loadInstitutions() {
        do {
            institutions = try sdk.getPaymentInstitutions()
        } catch {
            // Tratar erro (rede, autenticação, etc.)
            print("Falha ao carregar instituições: \(error)")
        }
    }
}
```

**Exibir instituições para o usuário:**


```swift
struct InstitutionPickerView: View {
    @ObservedObject var viewModel: EnrollmentViewModel
    
    var body: some View {
        List(viewModel.institutions) { institution in
            Button(action: { 
                viewModel.selectedInstitution = institution 
            }) {
                HStack {
                    AsyncImage(url: URL(string: institution.iconLogo))
                        .frame(width: 40, height: 40)
                    Text(institution.displayName)
                }
            }
        }
        .onAppear {
            viewModel.loadInstitutions()
        }
    }
}
```

### Passo 2: Solicitar Permissões

Solicite permissões de localização necessárias para avaliação de risco:


```swift
func requestPermissions() {
    sdk.requestPermission { granted in
        DispatchQueue.main.async {
            if let permissionGranted = granted as? Bool, permissionGranted {
                // Permissões concedidas, prossiga para o cadastro
                self.startEnrollment()
            } else {
                // Lidar com a negação de permissão
                self.showPermissionDeniedAlert()
            }
        }
    }
}
```

### Passo 3: Criar Inscrição

Crie a inscrição com a seguinte chamada de método (o SDK lida com a coleta de sinais de risco internamente):


```swift
func startEnrollment() {
    guard let institution = selectedInstitution else { return }
    
    do {
        let enrollment = try sdk.createEnrollment(
            cpf: userCPF,                           // CPF do usuário
            institution: institution.id,             // ID da instituição selecionada
            accountTenure: customerCreatedDate,      // Formato "YYYY-MM-DD"
            callbackUrl: "https://myapp.com/callback"
        )
        
        // Salvar ID da inscrição e ID do dispositivo para mais tarde
        self.enrollmentId = enrollment.id
        self.deviceId = enrollment.details.riskSignals.deviceId
        
        // Redirecionar usuário para a instituição
        if let redirectUrl = enrollment.details.redirectUrl {
            self.openInstitutionApp(url: redirectUrl)
        }
        
    } catch {
        // Tratar erro
        print("Falha na criação da inscrição: \(error)")
    }
}
```

Formato de Duração da Conta
O parâmetro `accountTenure` deve ser a data em que o usuário foi criado como um Cliente Belvo, no formato `YYYY-MM-DD`. Extraia isso do timestamp `created_at` do Cliente (primeiros 10 caracteres).

### Passo 4: Redirecionar para a Instituição

Abra o aplicativo da instituição usando o `redirect_url`:


```swift
func openInstitutionApp(url: String) {
    guard let url = URL(string: url) else { return }
    
    if UIApplication.shared.canOpenURL(url) {
        UIApplication.shared.open(url)
    }
}
```

A instituição irá redirecionar de volta para o seu `callbackUrl` com parâmetros OAuth.

### Passo 5: Completar o Cadastro Após Redirecionamento

Trate o callback OAuth no seu aplicativo e complete o cadastro:


```swift
// No seu SceneDelegate ou App delegate
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    
    // Passe a URL completa de callback para o SDK
    handleEnrollmentCallback(url: url)
}

func handleEnrollmentCallback(url: URL) {
    do {
        let enrollment = try sdk.completeEnrollmentAfterRedirection(
            callbackUrl: url.absoluteString  // O SDK analisa os parâmetros automaticamente
        )
        
        // Verifique se foi bem-sucedido
        if enrollment.status == "PENDING" {
            // Sucesso - prossiga para o registro FIDO
            self.getFidoOptions(enrollmentId: enrollment.id)
        } else if enrollment.status == "FAILED" {
            // Trate a falha
            self.showEnrollmentError(
                code: enrollment.statusReasonCode,
                message: enrollment.statusReasonMessage
            )
        }
        
    } catch {
        print("Falha ao completar o cadastro: \(error)")
    }
}
```

Alternativa: Parâmetros Manuais
Se preferir analisar a URL de callback você mesmo, pode passar os parâmetros individualmente:


```swift
let enrollment = try sdk.completeEnrollmentAfterRedirection(
    state: stateParam,
    code: codeParam,
    idToken: idTokenParam
)
```

### Passo 6: Obter Opções de Registro FIDO

Recupere as opções FIDO necessárias para o registro biométrico. O SDK faz a verificação automaticamente por até 5 minutos:


```swift
func getFidoOptions(enrollmentId: String) {
    // O SDK verifica automaticamente a cada 1 segundo por até 5 minutos
    if let fidoOptions = sdk.getFidoRegistrationOptions(enrollmentId: enrollmentId) {
        // Opções FIDO recebidas, prossiga para o registro biométrico
        self.startBiometricRegistration(fidoOptions: fidoOptions)
    } else {
        // Tempo de verificação esgotado (5 minutos se passaram)
        self.showTimeoutError()
    }
}
```

Verificação Automática
O método `getFidoRegistrationOptions()` lida com toda a lógica de verificação automaticamente. Ele verifica a cada 1 segundo por até 5 minutos, então você não precisa implementar nenhuma lógica de tentativa novamente.

### Passo 7: Registrar Biometria e Confirmar

Solicite ao usuário os dados biométricos e confirme o cadastro:


```swift
class EnrollmentViewModel: NSObject, ObservableObject {
    private let sdk: BiometricPixSDK
    private var enrollmentId: String?
    
    func startBiometricRegistration(fidoOptions: FidoRegistrationOptions) {
        do {
            try sdk.startRegistration(
                fidoResponseString: fidoOptions.toJsonString(),
                callback: self
            )
        } catch {
            print("Failed to start registration: \(error)")
        }
    }
}

// Implementar callback FIDO
extension EnrollmentViewModel: FidoRegistrationCallback {
    func onSuccess(credential: PublicKeyCredential, response: AuthenticatorAttestationResponse) {
        // O SDK lida automaticamente com a criação do payload
        guard let enrollmentId = self.enrollmentId else { return }
        
        let success = sdk.confirmEnrollment(
            enrollmentId: enrollmentId,
            credential: credential,
            response: response
        )
        
        if success {
            DispatchQueue.main.async {
                self.showEnrollmentSuccess()
            }
        } else {
            DispatchQueue.main.async {
                self.showEnrollmentError()
            }
        }
    }
    
    func onError(error: String) {
        DispatchQueue.main.async {
            self.showBiometricError(message: error)
        }
    }
}
```

Ciclo de Vida do View Model
Ao usar view models com callbacks no SwiftUI, declare-os como `@ObservedObject` ou `@StateObject` para evitar que sejam destruídos durante as re-renderizações da view:


```swift
struct EnrollmentView: View {
    @StateObject private var viewModel: EnrollmentViewModel
}
```

Cadastro Completo!
O dispositivo agora está cadastrado e pronto para pagamentos biométricos.

## Fluxo de Pagamento (4 Etapas)

Uma vez inscrito, iniciar pagamentos requer quatro chamadas de método (como você pode ver no diagrama de sequência abaixo):


```mermaid
sequenceDiagram
    autonumber

    participant User
    participant YourApp
    participant BiometricPixSDK
    participant BelvoAPI
    participant Institution

    Note over YourApp,BiometricPixSDK: Chamada 1: listEnrollments()
    User->>YourApp: Inicia pagamento
    YourApp->>BiometricPixSDK: listEnrollments(deviceId)
    BiometricPixSDK->>BelvoAPI: GET /enrollments/?device_id=...
    BelvoAPI-->>BiometricPixSDK: [Enrollment]
    BiometricPixSDK-->>YourApp: Lista de inscrições
    YourApp->>User: Exibir seletor de inscrição
    User-->>YourApp: Seleciona inscrição
    
    Note over YourApp,BiometricPixSDK: Chamada 2: createPaymentIntent()
    YourApp->>BiometricPixSDK: createPaymentIntent(payload)
    BiometricPixSDK->>BelvoAPI: POST /payment-intents/
    BelvoAPI-->>BiometricPixSDK: PaymentIntent (com opções FIDO)
    BiometricPixSDK-->>YourApp: Objeto PaymentIntent
    
    Note over YourApp,BiometricPixSDK: Chamada 3: startSigning() + collectRiskSignals()
    YourApp->>BiometricPixSDK: startSigning(fidoOptions, callback)
    BiometricPixSDK->>User: Solicitar biometria (Face ID/Touch ID)
    User-->>BiometricPixSDK: Fornece biometria
    BiometricPixSDK-->>YourApp: Asserção via callback
    YourApp->>BiometricPixSDK: collectRiskSignals(accountTenure)
    BiometricPixSDK-->>YourApp: RiskSignals
    
    Note over YourApp,BiometricPixSDK: Chamada 4: authorizePaymentIntent()
    YourApp->>BiometricPixSDK: authorizePaymentIntent(paymentIntentId, payload)
    BiometricPixSDK->>BelvoAPI: POST /payment-intents/{id}/authorize/
    BelvoAPI->>Institution: Processar pagamento
    Institution-->>BelvoAPI: Pagamento confirmado
    BelvoAPI-->>BiometricPixSDK: Pagamento SUCCEEDED
    BiometricPixSDK-->>YourApp: Sucesso na autorização (Boolean)
    YourApp->>User: Mostrar confirmação de pagamento
```

### Passo 1: Listar Inscrições

Busque todas as inscrições para o dispositivo atual e permita que o usuário selecione uma:


```swift
class PaymentViewModel: ObservableObject {
    private let sdk: BiometricPixSDK
    @Published var enrollments: [Enrollment] = []
    @Published var selectedEnrollment: Enrollment?
    
    func loadEnrollments(deviceId: String) {
        do {
            enrollments = try sdk.listEnrollments(deviceId: deviceId)
        } catch {
            print("Falha ao carregar inscrições: \(error)")
        }
    }
}
```

**Exibir inscrições para o usuário:**


```swift
struct EnrollmentSelectionView: View {
    @ObservedObject var viewModel: PaymentViewModel
    
    var body: some View {
        List(viewModel.enrollments) { enrollment in
            Button(action: { 
                viewModel.selectedEnrollment = enrollment 
            }) {
                HStack {
                    if let institution = enrollment.institution {
                        AsyncImage(url: URL(string: institution.iconLogo))
                            .frame(width: 40, height: 40)
                        VStack(alignment: .leading) {
                            Text(institution.displayName)
                            Text("Status: \(enrollment.status)")
                                .font(.caption)
                                .foregroundColor(.gray)
                        }
                    }
                }
            }
        }
        .onAppear {
            viewModel.loadEnrollments(deviceId: savedDeviceId)
        }
    }
}
```

### Passo 2: Criar Intenção de Pagamento

Crie uma intenção de pagamento com todos os detalhes do pagamento:


```swift
func createPayment(amount: Double, enrollmentId: String, beneficiaryAccountId: String) {
    let payload = CreatePaymentIntentPayload(
        amount: amount,
        customer: Customer(identifier: userCPF),  // CPF do usuário
        description: "Pagamento por serviços",
        statementDescription: "Compra ACME Corp",
        allowedPaymentMethodTypes: ["open_finance_biometric_pix"],
        paymentMethodDetails: PaymentMethodDetails(
            openFinanceBiometricPix: OpenFinanceBiometricPixPaymentMethodDetails(
                beneficiaryBankAccount: beneficiaryAccountId,
                enrollment: enrollmentId
            )
        ),
        confirm: true
    )
    
    do {
        let paymentIntent = try sdk.createPaymentIntent(payload: payload)
        
        // Salvar ID da intenção de pagamento
        self.paymentIntentId = paymentIntent.id
        
        // Extrair opções FIDO para o próximo passo
        if let fidoOptions = paymentIntent.paymentMethodInformation?.openFinanceBiometricPix?.fidoOptions {
            self.promptForBiometric(fidoOptions: fidoOptions)
        }
        
    } catch {
        print("Falha ao criar intenção de pagamento: \(error)")
    }
}
```

### Passo 3: Coletar Sinais Biométricos e de Risco

Solicite a autenticação biométrica e colete sinais de risco:


```swift
class PaymentViewModel: NSObject, ObservableObject {
    private let sdk: BiometricPixSDK
    private var paymentIntentId: String?
    private var riskSignals: RiskSignals?
    private var assertionResponse: AssertionResponse?
    
    func promptForBiometric(fidoOptions: FidoOptions) {
        // Converter opções FIDO para string JSON
        let fidoJsonString = fidoOptions.toJsonString()
        
        do {
            try sdk.startSigning(
                fidoResponseString: fidoJsonString,
                fallbackCredential: nil,  // Opcional: forneça se você tiver um
                callback: self
            )
        } catch {
            print("Falha ao iniciar assinatura: \(error)")
        }
    }
    
    func collectRiskSignals() {
        do {
            self.riskSignals = try sdk.collectRiskSignals(
                accountTenure: customerCreatedDate  // "YYYY-MM-DD"
            )
            
            // Assim que tivermos tanto a asserção quanto os sinais de risco, autorizar pagamento
            if assertionResponse != nil && riskSignals != nil {
                self.authorizePayment()
            }
        } catch {
            print("Falha ao coletar sinais de risco: \(error)")
        }
    }
}

// Implementar callback de autenticação FIDO
extension PaymentViewModel: FidoAuthenticationCallback {
    func onSuccess(response: AssertionResponse) {
        // Armazenar resposta de asserção
        self.assertionResponse = response
        
        // Coletar sinais de risco
        self.collectRiskSignals()
    }
    
    func onError(error: String) {
        DispatchQueue.main.async {
            self.showPaymentError(message: error)
        }
    }
}
```

### Passo 4: Autorizar Pagamento

Autorize o pagamento com os dados coletados:


```swift
func authorizePayment() {
    guard let paymentIntentId = self.paymentIntentId,
          let riskSignals = self.riskSignals,
          let assertion = self.assertionResponse else {
        return
    }
    
    let payload = AuthorizePaymentIntentPayload(
        platform: "ios",
        riskSignals: riskSignals,
        assertion: assertion
    )
    
    let success = sdk.authorizePaymentIntent(
        paymentIntentId: paymentIntentId,
        payload: payload
    )
    
    DispatchQueue.main.async {
        if success {
            self.showPaymentSuccess()
        } else {
            self.showPaymentError(message: "Authorization failed")
        }
    }
}
```

Fluxo de Pagamento Completo!
O pagamento agora está autorizado e em processamento. Você precisa monitorar eventos de webhook para acompanhar seu status final.

## Tratamento de Erros

Todos os métodos do SDK que realizam operações de rede podem lançar exceções. Certifique-se de tratá-las adequadamente:


```swift
do {
    let institutions = try sdk.getPaymentInstitutions()
    // Sucesso
} catch let error as BiometricPixSDKError {
    switch error {
    case .networkError(let message):
        // Tratar problemas de rede
        print("Erro de rede: \(message)")
    case .authenticationError:
        // Tratar token inválido ou expirado
        print("Falha na autenticação - o token pode estar expirado")
    case .invalidParameters(let message):
        // Tratar entrada inválida
        print("Parâmetros inválidos: \(message)")
    case .unknown(let message):
        // Tratar erros desconhecidos
        print("Erro: \(message)")
    }
} catch {
    print("Erro inesperado: \(error)")
}
```

## Webhooks

Embora o SDK lide com a maior parte do fluxo de trabalho, você ainda deve ouvir as notificações de webhook para lidar com atualizações assíncronas:

- **Mudanças no status de inscrição:** tipo de webhook `ENROLLMENTS`
- **Mudanças no status de pagamento:** tipo de webhook `PAYMENT_INTENTS`


Para a documentação completa de webhooks, veja Webhooks de Pagamentos (Brasil).

## Referência de Método SDK

### Inicialização

**`BiometricPixSDK(accessToken: String)`**

- Cria uma nova instância do SDK com o access token fornecido
- Deve ser inicializado uma vez e reutilizado ao longo do seu aplicativo
- Access token obtido a partir do endpoint `/payments/api/widget-token/`


**`cleanup()`**

- Libera os recursos do SDK
- Chame em `deinit` ou quando o usuário fizer logout


### Métodos de Inscrição

**`getPaymentInstitutions() throws -> [Institution]`**

- Busca todas as instituições que suportam pagamentos biométricos
- Retorna um array de objetos `Institution` com `id`, `displayName`, `iconLogo`, etc.
- Lança exceções em erros de rede ou autenticação


**`createEnrollment(cpf: String, institution: String, accountTenure: String, callbackUrl: String) throws -> Enrollment`**

- Cria a inscrição e coleta sinais de risco automaticamente
- `cpf`: Número de CPF do usuário
- `institution`: ID da instituição obtido de `getPaymentInstitutions()`
- `accountTenure`: Data de criação do cliente no formato "YYYY-MM-DD"
- `callbackUrl`: Deep link para o callback OAuth (deve ser registrado em applinks)
- Retorna um objeto `Enrollment` com `id`, `redirect_url`, `device_id`


**`completeEnrollmentAfterRedirection(callbackUrl: String) throws -> Enrollment`**

- Completa a inscrição após o callback OAuth da instituição
- Analisa automaticamente os parâmetros OAuth da URL completa de callback
- Alternativa: `completeEnrollmentAfterRedirection(state: String, code: String, idToken: String)`


**`getFidoRegistrationOptions(enrollmentId: String) -> FidoRegistrationOptions?`**

- Faz polling para opções FIDO (tentativa automática: intervalo de 1 segundo, timeout de 5 minutos)
- Retorna `FidoRegistrationOptions` quando pronto
- Retorna `nil` se o polling expirar


**`startRegistration(fidoResponseString: String, callback: FidoRegistrationCallback) throws`**

- Inicia o fluxo de registro biométrico (Face ID/Touch ID)
- `fidoResponseString`: String JSON de `FidoRegistrationOptions.toJsonString()`
- `callback`: Delegate para receber callbacks de sucesso/erro


**`confirmEnrollment(enrollmentId: String, credential: PublicKeyCredential, response: AuthenticatorAttestationResponse) -> Bool`**

- Confirma a inscrição com credencial FIDO
- Retorna `true` em caso de sucesso, `false` em caso de falha


### Métodos de Pagamento

**`listEnrollments(deviceId: String) throws -> [Enrollment]`**

- Busca todas as inscrições para um dispositivo
- Retorna um array de objetos `Enrollment` com dados enriquecidos da instituição
- Filtrar por `status == "SUCCEEDED"` para mostrar apenas inscrições ativas


**`createPaymentIntent(payload: CreatePaymentIntentPayload) throws -> PaymentIntent`**

- Cria uma intenção de pagamento
- Retorna `PaymentIntent` com `id` e `paymentMethodInformation.openFinanceBiometricPix.fidoOptions`


**`startSigning(fidoResponseString: String, fallbackCredential: String?, callback: FidoAuthenticationCallback) throws`**

- Inicia a autenticação biométrica para pagamento
- `fallbackCredential`: Credencial opcional para cenários de nova tentativa
- `callback`: Delegado para receber a resposta de asserção


**`collectRiskSignals(accountTenure: String) throws -> RiskSignals`**

- Coleta impressões digitais do dispositivo e sinais de segurança
- `accountTenure`: Data de criação do cliente no formato "YYYY-MM-DD"
- Retorna objeto `RiskSignals` para payload de autorização


**`authorizePaymentIntent(paymentIntentId: String, payload: AuthorizePaymentIntentPayload) -> Bool`**

- Autoriza pagamento com asserção biométrica e sinais de risco
- Retorna `true` em caso de sucesso, `false` em caso de falha