@lina-openx/react-native-lina-pay-sdk
v1.0.1
Published
Create Open Finance Payments EasilyCreate Open Finance Payments
Readme
react-native-lina-pay-sdk
SDK React Native para integração com Lina Open Finance - Facilitando a criação de pagamentos através do Open Finance.
📖 Documentação
- Guia do Usuário Completo - Documentação detalhada para implementação
- Diagramas de Fluxo - Diagramas visuais do fluxo de pagamento
🚀 Instalação
npm install react-native-lina-pay-sdkou
yarn add react-native-lina-pay-sdk📋 Requisitos
- React Native >= 0.83.0
- Node >= 20
🔧 Uso
Configuração Inicial
Por padrão, o SDK está configurado para usar o ambiente de homologação (HML). Para produção ou outros ambientes, configure as URLs base:
import LinaPaySdk from 'react-native-lina-pay-sdk';
// Configurar para produção
LinaPaySdk.configure({
iamBaseUrl: 'https://iam.prod.linaob.com.br',
apiBaseUrl: 'https://embedded-payment-manager.prod.linaob.com.br'
});Listagem de Participantes
Obtenha a lista de instituições financeiras participantes do Open Finance:
import { getParticipants, type Participant, LinaPayError } from 'react-native-lina-pay-sdk';
async function fetchParticipants() {
try {
const participants = await getParticipants({
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
});
console.log(`${participants.length} participantes encontrados`);
participants.forEach(participant => {
console.log(`${participant.customerFriendlyName} - ${participant.registrationNumber}`);
});
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro Lina Pay:', error.message, error.statusCode);
} else {
console.error('Erro desconhecido:', error);
}
}
}Criação de Consentimento de Pagamento
Crie um consentimento para iniciar um pagamento via Open Finance:
import { createConsent, type CreateConsentRequest, LinaPayError } from 'react-native-lina-pay-sdk';
async function createPaymentConsent() {
try {
const payload: CreateConsentRequest = {
organisationId: 'c8f0bf49-4744-4933-8960-7add6e590841',
authorisationServerId: 'c8f0bf49-4744-4933-8960-7add6e590841',
payment: {
redirectUri: 'http://example.com/redirect',
value: 1500.50,
creditor: {
name: 'John Doe',
personType: 'PESSOA_NATURAL',
cpfCnpj: '12345678901234',
accountNumber: '1234567890',
accountIssuer: '0001',
accountPixKey: '[email protected]',
accountIspb: '12345678',
accountType: 'CACC'
}
},
platform: 'APP'
};
const consent = await createConsent(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
payload
);
console.log('Consentimento criado:', consent.consentId);
console.log('Status:', consent.status);
console.log('URL de redirecionamento:', consent.redirectUrl);
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao criar consentimento:', error.message);
}
}
}Criação de Pagamento
Após o usuário autorizar o consentimento, crie o pagamento usando os parâmetros retornados:
import { createPayment, type CreatePaymentRequest, LinaPayError } from 'react-native-lina-pay-sdk';
async function processPayment() {
try {
// state, code e idToken são retornados após autorização do consentimento
const payment = await createPayment(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
{
state: 'rumUP',
code: '1RDYVFQnPn721',
idToken: 'eyJhbGciOiJQUz',
tenantId: 'tenantId'
}
);
console.log('Pagamento criado:', payment.id);
console.log('Status:', payment.status);
console.log('Valor:', payment.value);
console.log('Itens de pagamento:', payment.payments.length);
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao criar pagamento:', error.message);
}
}
}Enrollment (Cadastro de Dispositivo)
O Enrollment permite cadastrar um dispositivo do usuário usando autenticação FIDO2/Passkeys. Uma vez cadastrado, o usuário pode realizar pagamentos sem precisar redirecionar para o banco a cada transação.
Criar Enrollment
import { createEnrollment, type CreateEnrollmentRequest, LinaPayError } from 'react-native-lina-pay-sdk';
import { Linking } from 'react-native';
async function createDeviceEnrollment() {
try {
const enrollment = await createEnrollment(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
{
organisationId: 'org-uuid',
authorisationServerId: 'auth-uuid',
enrollment: {
document: '12345678901', // CPF do usuário
deviceName: 'iPhone do João',
debtor: {
accountNumber: '123456',
accountIssuer: '0001',
accountIspb: '12345678',
accountType: 'CACC'
}
},
redirectUri: 'https://seu-app.com/enrollment-callback'
}
);
console.log('Enrollment criado:', enrollment.id);
// Redirecionar usuário para autorização
if (enrollment.redirectUrl) {
Linking.openURL(enrollment.redirectUrl);
}
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao criar enrollment:', error.message);
}
}
}Registrar Dispositivo (após callback)
Após o usuário autorizar no banco e receber o callback, registre o dispositivo:
import { registerDevice, type RegisterDeviceRequest, LinaPayError } from 'react-native-lina-pay-sdk';
import { Platform } from 'react-native';
async function registerDeviceAfterCallback(state: string, code: string, idToken: string) {
try {
const platform = Platform.OS === 'ios' ? 'IOS' : Platform.OS === 'android' ? 'ANDROID' : 'WEB';
const enrollment = await registerDevice(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
{
state,
code,
idToken,
tenantId: 'seu-subtenant-id',
platform
}
);
console.log('Dispositivo registrado:', enrollment.enrollmentId);
console.log('Status:', enrollment.status); // Deve ser 'AUTHORISED'
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao registrar dispositivo:', error.message);
}
}
}Listar Enrollments
import { getEnrollmentList, LinaPayError } from 'react-native-lina-pay-sdk';
async function listUserEnrollments() {
try {
const enrollmentList = await getEnrollmentList(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
'12345678901' // CPF do usuário
);
console.log('Total de enrollments:', enrollmentList.enrollments.length);
enrollmentList.enrollments.forEach(enrollment => {
console.log(`- ${enrollment.enrollmentId}: ${enrollment.status}`);
});
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao listar enrollments:', error.message);
}
}
}Revogar Enrollment
import { revokeEnrollment, LinaPayError } from 'react-native-lina-pay-sdk';
async function removeEnrollment() {
try {
await revokeEnrollment(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
'enrollment-id-aqui'
);
console.log('Enrollment revogado com sucesso');
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao revogar enrollment:', error.message);
}
}
}Pagamento com Enrollment
Após ter um enrollment ativo, você pode realizar pagamentos sem redirecionar o usuário ao banco. O pagamento é autorizado usando autenticação biométrica FIDO2/Passkeys:
import { createPaymentWithEnrollment, type PaymentWithEnrollmentRequest, LinaPayError } from 'react-native-lina-pay-sdk';
import { Platform } from 'react-native';
async function payWithEnrollment() {
try {
const platform = Platform.OS === 'ios' ? 'IOS' : Platform.OS === 'android' ? 'ANDROID' : 'WEB';
const payment = await createPaymentWithEnrollment(
{
subtenantId: 'seu-subtenant-id',
subtenantSecret: 'seu-subtenant-secret'
},
{
enrollmentId: 'enrollment-id-ativo',
organisationId: 'org-uuid',
authorisationServerId: 'auth-uuid',
payment: {
value: 1500.50,
details: 'Pagamento de serviço',
externalId: 'payment-123',
redirectUri: 'https://seu-app.com/payment-success',
cpfCnpj: '12345678901',
creditor: {
name: 'Empresa Beneficiária',
personType: 'PESSOA_JURIDICA',
cpfCnpj: '12345678000190',
accountNumber: '123456',
accountIssuer: '0001',
accountPixKey: '[email protected]',
accountIspb: '12345678',
accountType: 'CACC'
},
txId: []
},
fidoSignOptions: {
rp: 'app.linaopenx.com.br',
platform
}
}
);
console.log('Pagamento processado:', payment.id);
console.log('Consent ID:', payment.consentId);
// O usuário será solicitado a autorizar com biometria automaticamente
} catch (error) {
if (error instanceof LinaPayError) {
console.error('Erro ao processar pagamento:', error.message);
}
}
}Vantagens do Pagamento com Enrollment:
- ⚡ Mais rápido: sem redirecionamento ao banco
- 🔒 Seguro: autenticação biométrica obrigatória
- 📱 Melhor UX: tudo acontece dentro do app
- 🔄 Ideal para pagamentos recorrentes
Exemplo Completo com React
import React, { useState } from 'react';
import { View, Button, FlatList, Text } from 'react-native';
import { getParticipants, type Participant } from 'react-native-lina-pay-sdk';
export default function ParticipantsList() {
const [participants, setParticipants] = useState<Participant[]>([]);
const [loading, setLoading] = useState(false);
const loadParticipants = async () => {
setLoading(true);
try {
const result = await getParticipants({
subtenantId: process.env.SUBTENANT_ID!,
subtenantSecret: process.env.SUBTENANT_SECRET!
});
setParticipants(result);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
return (
<View>
<Button
title="Carregar Participantes"
onPress={loadParticipants}
disabled={loading}
/>
<FlatList
data={participants}
keyExtractor={(item) => `${item.organisationId}-${item.authorisationServerId}`}
renderItem={({ item }) => (
<View>
<Text>{item.customerFriendlyName}</Text>
<Text>{item.legalEntityName}</Text>
<Text>CNPJ: {item.registrationNumber}</Text>
</View>
)}
/>
</View>
);
}📚 API Reference
createConsent(credentials, payload)
Cria um consentimento de pagamento via Open Finance.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
payload(objeto, obrigatório):organisationId(string, obrigatório): UUID da organização participanteauthorisationServerId(string, obrigatório): UUID do servidor de autorizaçãopayment(objeto, obrigatório):redirectUri(string, obrigatório): URL de redirecionamento após autorizaçãovalue(number, obrigatório): Valor do pagamento (deve ser positivo)creditor(objeto, obrigatório):name(string, obrigatório): Nome do beneficiáriopersonType(string, obrigatório): Tipo de pessoa ('PESSOA_NATURAL' | 'PESSOA_JURIDICA')cpfCnpj(string, obrigatório): CPF (11 dígitos) ou CNPJ (14 dígitos)accountNumber(string, obrigatório): Número da contaaccountIssuer(string, obrigatório): AgênciaaccountPixKey(string, obrigatório): Chave PIXaccountIspb(string, obrigatório): Código ISPBaccountType(string, obrigatório): Tipo de conta ('CACC' | 'SLRY' | 'SVGS' | 'TRAN')
details(string, opcional): Detalhes do pagamentoexternalId(string, opcional): ID externocpfCnpj(string, opcional): CPF/CNPJ do pagadordebitor(objeto, opcional): Informações do pagadorschedule(objeto, opcional): Agendamento do pagamentotxId(string | string[], opcional): ID(s) da transação
redirectUri(string, opcional): URL de redirecionamento alternativaplatform(string, opcional): Plataforma ('APP' | 'WEB')
Retorna: Promise<CreateConsentResponse>
Estrutura do CreateConsentResponse:
interface CreateConsentResponse {
consentId: string; // URN do consentimento criado
redirectUrl: string; // URL para autorização do usuário
id: string; // UUID interno do consentimento
}Exemplo de resposta:
{
"consentId": "urn:nubank:796a30aa-0a3c-3f60-acb1-d6097864267e",
"redirectUrl": "https://nuapp.nubank.com.br/open-banking/authorize?request_uri=...",
"id": "60735a9c-0036-4b1a-9247-2fd8ef651c7b"
}Exemplo com Agendamento:
const consentWithSchedule = await createConsent(credentials, {
organisationId: 'org-uuid',
authorisationServerId: 'auth-uuid',
payment: {
redirectUri: 'http://example.com/redirect',
value: 1500.50,
creditor: { /* ... */ },
schedule: {
single: {
date: '2024-09-01' // Pagamento único em data específica
}
}
}
});Tipos de Agendamento Disponíveis:
single: Pagamento único em data específicadaily: Pagamentos diários recorrentesweekly: Pagamentos semanais recorrentesmonthly: Pagamentos mensais recorrentescustom: Datas customizadas
createPayment(credentials, payload)
Cria um pagamento após validação do consentimento via Open Finance.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
payload(objeto, obrigatório):state(string, obrigatório): Estado retornado após autorização do consentimentocode(string, obrigatório): Código retornado após autorização do consentimentoidToken(string, obrigatório): Token ID retornado após autorização do consentimentotenantId(string, obrigatório): ID do tenant
Retorna: Promise<CreatePaymentResponse>
Estrutura do CreatePaymentResponse:
interface CreatePaymentResponse {
id: string; // UUID do pagamento
type: PaymentType; // Tipo do pagamento (ex: 'NOW')
createDateTime: string; // Data/hora de criação (ISO 8601)
externalId?: string; // ID externo
externalComment?: string; // Comentário externo
lastChangedDateTime: string; // Data/hora da última alteração (ISO 8601)
status: PaymentStatus; // Status do pagamento (ex: 'CONSUMIDO', 'PAGO')
tenantId: string; // ID do tenant
cpfCnpj: string; // CPF/CNPJ do pagador
redirectUri: string; // URL de redirecionamento
value: string; // Valor do pagamento (como string)
consentId: string; // URN do consentimento associado
creditor: PaymentCreditor; // Informações do beneficiário
debitor?: PaymentDebitor; // Informações do pagador
payments: PaymentItem[]; // Array de itens de pagamento
}
interface PaymentItem {
endToEndId: string; // ID end-to-end da transação
id: string; // UUID do item de pagamento
dueDate: string; // Data de vencimento (ISO 8601)
externalComment?: string; // Comentário externo
txId: string | null; // ID da transação (pode ser null)
status: PaymentItemStatus; // Status do item (ex: 'PAGO')
externalPaymentId: string; // ID externo do pagamento
}Exemplo de uso:
import { createPayment, type CreatePaymentRequest } from 'react-native-lina-pay-sdk';
const payment = await createPayment(
{
subtenantId: 'your-subtenant-id',
subtenantSecret: 'your-subtenant-secret'
},
{
state: 'rumUP',
code: '1RDYVFQnPn721',
idToken: 'eyJhbGciOiJQUz',
tenantId: 'tenantId'
}
);
console.log('Payment ID:', payment.id);
console.log('Status:', payment.status);
console.log('Value:', payment.value);
console.log('Payments count:', payment.payments.length);Observações:
- Este método deve ser chamado após o usuário autorizar o consentimento
- Os parâmetros
state,codeeidTokensão retornados após a autorização do consentimento - O valor do pagamento é retornado como string pela API
- O array
paymentscontém os detalhes de cada pagamento individual processado
getParticipants(credentials)
Obtém a lista de participantes registrados no Open Finance.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
Retorna: Promise<Participant[]>
Estrutura do Participant:
interface Participant {
organisationId: string; // UUID da organização
organisationName: string; // Nome da organização
legalEntityName: string; // Razão social
registrationNumber: string; // CNPJ
authorisationServerId: string; // UUID do servidor de autorização
customerFriendlyName: string; // Nome amigável
customerFriendlyLogoUri: string; // URL do logotipo
}Observações:
- Participantes com múltiplos servidores de autorização resultam em múltiplas entradas na lista
- Participantes sem servidores de autorização são automaticamente filtrados
- O token de autenticação é gerenciado automaticamente pelo SDK (com cache)
createEnrollment(credentials, payload)
Cria um enrollment inicial para registrar um dispositivo do usuário.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
payload(objeto, obrigatório):organisationId(string, obrigatório): UUID da organização participanteauthorisationServerId(string, obrigatório): UUID do servidor de autorizaçãoenrollment(objeto, obrigatório):document(string, opcional): CPF do usuárioexternalId(string, opcional): ID externodeviceName(string, opcional): Nome do dispositivodebtor(objeto, obrigatório): Dados da conta do pagadoraccountNumber(string): Número da contaaccountIssuer(string): AgênciaaccountIspb(string): Código ISPBaccountType(string): Tipo de conta ('CACC' | 'SLRY' | 'SVGS' | 'TRAN')
redirectUri(string, obrigatório): URL do callback após autorizaçãopaymentId(string, opcional): ID do pagamento relacionado
Retorna: Promise<CreateEnrollmentResponse>
Estrutura do CreateEnrollmentResponse:
interface CreateEnrollmentResponse {
id: string; // UUID do enrollment
redirectUrl?: string; // URL para redirecionar o usuário
consentId?: string | null; // ID do consentimento (pode ser null)
}registerDevice(credentials, payload)
Registra um dispositivo usando autenticação FIDO2/Passkeys após o callback de autorização.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
payload(objeto, obrigatório):state(string): Estado retornado no callbackcode(string): Código retornado no callbackidToken(string): Token ID retornado no callbacktenantId(string): Mesmo valor do subtenantIdplatform(string): Plataforma ('ANDROID' | 'IOS' | 'WEB' | 'BROWSER' | 'CROSS_PLATFORM')rp(string, opcional): Relying Party ID
Retorna: Promise<Enrollment>
Estrutura do Enrollment:
interface Enrollment {
enrollmentId: string;
creationDateTime: string;
status: 'AWAITING_RISK_SIGNALS' | 'AWAITING_ACCOUNT_HOLDER_VALIDATION' |
'AWAITING_ENROLLMENT' | 'AUTHORISED' | 'REJECTED' | 'REVOKED';
statusUpdateDateTime: string;
permissions: 'PAYMENTS_INITIATE';
expirationDateTime: string | null;
// ... outros campos
}Observações:
- O dispositivo deve suportar FIDO2/Passkeys
- O usuário precisará autorizar com biometria (Face ID, Touch ID, etc.)
- O enrollment só estará pronto quando o status for
AUTHORISED
getEnrollmentList(credentials, cpf)
Lista todos os enrollments de um usuário pelo CPF.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
cpf(string, obrigatório): CPF do usuário (11 dígitos)
Retorna: Promise<EnrollmentList>
Estrutura do EnrollmentList:
interface EnrollmentList {
id: string;
username: string;
subTenant: string;
enrollments: EnrollmentUser[];
}revokeEnrollment(credentials, enrollmentId)
Revoga um enrollment, desativando o dispositivo cadastrado.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
enrollmentId(string, obrigatório): ID do enrollment a ser revogado
Retorna: Promise<RevokeEnrollmentResponse>
createPaymentWithEnrollment(credentials, payload)
Cria um pagamento usando um enrollment ativo, sem necessidade de redirecionamento ao banco.
Parâmetros:
credentials(objeto, obrigatório):subtenantId(string): ID do subtenant fornecido pela LinasubtenantSecret(string): Secret do subtenant fornecido pela Lina
payload(objeto, obrigatório):enrollmentId(string, obrigatório): ID do enrollment ativoorganisationId(string, obrigatório): UUID da organização participanteauthorisationServerId(string, obrigatório): UUID do servidor de autorizaçãopaymentId(string, opcional): ID do pagamento se já foi criadopayment(objeto, opcional): Dados do pagamento (similar aocreateConsent)fidoSignOptions(objeto, obrigatório):rp(string): Relying Party IDplatform(string): Plataforma ('ANDROID' | 'IOS' | 'WEB' | 'BROWSER' | 'CROSS_PLATFORM')
Retorna: Promise<PaymentWithEnrollmentResponse>
Observações:
- Esta função realiza internamente: criação do consentimento, obtenção de opções FIDO, solicitação de biometria, assinatura e autorização
- O usuário será solicitado a autorizar com biometria automaticamente
- O enrollment deve estar com status
AUTHORISED
configure(config)
Configura as URLs base do SDK para diferentes ambientes.
Parâmetros:
config(objeto):iamBaseUrl(string, opcional): URL base do serviço de autenticação IAMapiBaseUrl(string, opcional): URL base da API do Embedded Payment Manager
Valores padrão (Homologação):
{
iamBaseUrl: 'https://iam.hml.linaob.com.br',
apiBaseUrl: 'https://embedded-payment-manager.hml.linaob.com.br'
}LinaPayError
Classe de erro customizada para tratamento de erros do SDK.
Propriedades:
message(string): Mensagem de errostatusCode(número, opcional): Código HTTP do erro (se aplicável)originalError(unknown, opcional): Erro original que causou o LinaPayError
🔐 Autenticação
O SDK gerencia automaticamente a autenticação OAuth2 com o servidor IAM:
- Token de acesso é obtido usando as credenciais fornecidas
- Token é cacheado e reutilizado enquanto válido
- Renovação automática do token quando expira (5 minutos antes da expiração real)
⚠️ Tratamento de Erros
Todos os métodos podem lançar LinaPayError nas seguintes situações:
- Credenciais inválidas:
statusCode: 401ou403 - Erro de rede: Timeout ou sem conexão
- Erro do servidor:
statusCode: 500+ - Validação de payload: Campos obrigatórios ausentes ou inválidos
- Validação de formato: CPF/CNPJ, URLs, datas ou valores numéricos inválidos
Exemplo de tratamento:
import { LinaPayError } from 'react-native-lina-pay-sdk';
try {
const consent = await createConsent(credentials, payload);
} catch (error) {
if (error instanceof LinaPayError) {
// Erros de validação (sem statusCode)
if (!error.statusCode) {
console.error('Erro de validação:', error.message);
// Ex: "payment.value must be greater than zero"
// Ex: "payment.creditor.cpfCnpj must be a valid CPF or CNPJ"
return;
}
// Erros HTTP
switch (error.statusCode) {
case 400:
console.error('Payload inválido:', error.message);
break;
case 401:
case 403:
console.error('Credenciais inválidas');
break;
case 500:
console.error('Erro no servidor');
break;
default:
console.error('Erro:', error.message);
}
}
}🧪 Desenvolvimento
Rodando o Exemplo
O projeto inclui um app de exemplo que demonstra o uso do SDK:
# Instalar dependências
yarn
# Buildar o SDK
yarn prepare
# Rodar o exemplo no Android
yarn example android
# Rodar o exemplo no iOS
yarn example iosTestes
# Rodar testes unitários
yarn test
# Verificar tipos TypeScript
yarn typecheck
# Lint
yarn lintEstrutura do Projeto
src/
├── config/
│ └── environment.ts # Configuração de URLs
├── controllers/
│ ├── consent.controller.ts # Controller de consentimentos
│ ├── enrollment.controller.ts # Controller de enrollments
│ ├── participants.controller.ts # Controller de participantes
│ └── payment.controller.ts # Controller de pagamentos
├── services/
│ ├── auth.service.ts # Autenticação OAuth2
│ ├── consent.service.ts # API de consentimentos
│ ├── enrollment.service.ts # API de enrollments
│ ├── fido.service.ts # Serviço FIDO2/Passkeys
│ ├── participants.service.ts # API de participantes
│ └── payment.service.ts # API de pagamentos
├── types/
│ ├── auth.types.ts # Tipos de autenticação
│ ├── consent.types.ts # Tipos de consentimento
│ ├── enrollment.types.ts # Tipos de enrollment
│ ├── fido.types.ts # Tipos FIDO
│ ├── participants.types.ts # Tipos de participantes
│ ├── payment.types.ts # Tipos de pagamento
│ └── index.ts # Re-exports
├── utils/
│ ├── enrollment.utils.ts # Utilitários de enrollment
│ └── http.utils.ts # Utilidades HTTP
└── index.tsx # API pública do SDKDesenvolvido por Lina OpenX com ❤️
