npm package: @lina-openx/web-lina-pay-sdk
Description: Create Open Finance Payments Easily
Author: Lina OpenX
Latest version: 1.0.7

# @lina-openx/web-lina-pay-sdk

SDK para criação de pagamentos Open Finance de forma simples e integrada.

## 📋 Descrição

O **@lina-openx/web-lina-pay-sdk** é um SDK TypeScript desenvolvido para facilitar a integração com a plataforma Lina OpenX para criação e gerenciamento de pagamentos Open Finance. O SDK oferece uma interface simples e type-safe para realizar operações como:

- Criação de consentimentos de pagamento
- Criação de solicitações de pagamento (payment request)
- Consulta dos detalhes de uma solicitação de pagamento pelo identificador
- Criação de pagamentos
- Gerenciamento de enrollments (cadastros de dispositivos)
- Consulta de participantes
- Integração com FIDO2/WebAuthn para autenticação segura

## 📦 Instalação

```bash
npm install @lina-openx/web-lina-pay-sdk
```

ou

```bash
yarn add @lina-openx/web-lina-pay-sdk
```

ou

```bash
pnpm add @lina-openx/web-lina-pay-sdk
```

## 🚀 Como Usar

### Importação

```typescript
import {
  configure,
  createConsent,
  createPaymentRequest,
  getPaymentRequest,
  createPayment,
  createEnrollment,
  getEnrollmentList,
  revokeEnrollment,
  registerDevice,
  createPaymentWithEnrollment,
  getParticipants,
  LinaPayError
} from '@lina-openx/web-lina-pay-sdk'
```

### Configuração Inicial

Antes de usar o SDK, você pode configurar as URLs base para diferentes ambientes (homologação ou produção):

```typescript
import { configure } from '@lina-openx/web-lina-pay-sdk'

// Configurar para produção
configure({
  iamBaseUrl: 'https://iam.linaob.com.br',
  apiBaseUrl: 'https://embedded-payment-manager.linaob.com.br'
})

// Configurar para homologação (padrão)
configure({
  iamBaseUrl: 'https://iam.hml.linaob.com.br',
  apiBaseUrl: 'https://embedded-payment-manager.hml.linaob.com.br'
})
```

## 📚 Métodos Disponíveis

### 1. `configure(config: Partial<LinaPayConfig>)`

Configura as URLs base do SDK para diferentes ambientes.

**Parâmetros:**
- `config`: Objeto parcial com as configurações:
  - `iamBaseUrl` (string, opcional): URL base do serviço de IAM
  - `apiBaseUrl` (string, opcional): URL base da API de pagamentos

**Exemplo:**
```typescript
configure({
  iamBaseUrl: 'https://iam.linaob.com.br',
  apiBaseUrl: 'https://embedded-payment-manager.linaob.com.br'
})
```

---

### 2. `createConsent(credentials, payload)`

Cria um consentimento de pagamento Open Finance.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant:
  - `subtenantId` (string): ID do subtenant
  - `subtenantSecret` (string): Secret do subtenant
- `payload`: Objeto `CreateConsentRequest` com:
  - `organisationId` (string): ID da organização
  - `authorisationServerId` (string): ID do servidor de autorização
  - `payment` (objeto): Detalhes do pagamento
  - `redirectUri` (string, opcional): URI de redirecionamento
  - `platform` (string, opcional): Plataforma ('APP' | 'WEB')

**Retorna:** `Promise<CreateConsentResponse>` com `consentId` e `redirectUrl`

**Exemplo:**
```typescript
const consent = await createConsent(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  {
    organisationId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    authorisationServerId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    payment: {
      redirectUri: 'https://exemplo.com/redirect',
      value: 1500.50,
      creditor: {
        name: 'João Silva',
        personType: 'PESSOA_NATURAL',
        cpfCnpj: '12345678901',
        accountNumber: '12345-6',
        accountIssuer: '0001',
        accountPixKey: 'joao@exemplo.com',
        accountIspb: '12345678',
        accountType: 'CACC'
      }
    },
    platform: 'WEB'
  }
)

console.log('Consent ID:', consent.consentId)
console.log('Redirect URL:', consent.redirectUrl)
```

**Exemplo com agendamento:**
```typescript
const consent = await createConsent(
  credentials,
  {
    organisationId: 'org-id',
    authorisationServerId: 'auth-id',
    payment: {
      redirectUri: 'https://exemplo.com/redirect',
      value: 100.00,
      creditor: { /* ... */ },
      schedule: {
        monthly: {
          dayOfMonth: 15,
          startDate: '2024-01-15',
          quantity: 12
        }
      }
    }
  }
)
```

---

### 3. `createPayment(credentials, payload)`

Cria um pagamento após o consentimento ser autorizado.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `payload`: Objeto `CreatePaymentRequest` com:
  - `state` (string): Estado do fluxo OAuth
  - `code` (string): Código de autorização
  - `idToken` (string): Token de identificação
  - `tenantId` (string): ID do tenant

**Retorna:** `Promise<CreatePaymentResponse>` com detalhes do pagamento

**Exemplo:**
```typescript
const payment = await createPayment(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  {
    state: 'rumUP',
    code: '1RDYVFQnPn721',
    idToken: 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...',
    tenantId: 'tenant-id-123'
  }
)

console.log('Payment ID:', payment.id)
console.log('Status:', payment.status)
console.log('Value:', payment.value)
```

---

### 4. `createPaymentRequest(credentials, payload)`

Cria uma **solicitação de pagamento** na API (`POST` no endpoint de payment request). O fluxo é distinto de `createPayment`: aqui você envia os dados do pagamento (valor, credor, URI de retorno etc.) e recebe um identificador e uma `redirectUri` para continuar o fluxo no ambiente da detentora. O token de acesso é obtido automaticamente a partir das credenciais do subtenant.

**Parâmetros:**

- `credentials`: objeto `LinaPayCredentials` (`subtenantId`, `subtenantSecret`)
- `payload`: objeto `CreatePaymentRequestDTO` validado antes do envio:
  - `details` (string): descrição ou detalhes do pagamento
  - `redirectUri` (string): URL de redirecionamento após o fluxo
  - `cpfCnpj` (string): CPF ou CNPJ do pagador (formato livre; a API pode normalizar)
  - `value` (number): valor do pagamento
  - `creditor` (objeto): dados do favorecido, alinhados ao tipo `Creditor` do consentimento:
    - `name`, `personType` (`PESSOA_NATURAL` | `PESSOA_JURIDICA`), `cpfCnpj`, `accountNumber`, `accountIssuer`, `accountIspb`, `accountType` (`CACC` | `SLRY` | `SVGS` | `TRAN`)
    - `accountPixKey` (string, opcional)
  - `txId` (string ou array de strings, opcional): identificador(es) de transação Pix, se aplicável
  - `externalId` (string, opcional): identificador externo
  - `schedule` (objeto): na validação atual do SDK, a chave `schedule` deve estar presente; pode ser um objeto vazio `{}` ou conter **apenas um** dos tipos de agenda abaixo (campos internos conforme validação):
    - `single`: `{ date }` (data `YYYY-MM-DD`)
    - `daily`: `{ startDate, quantity }` (`quantity` numérico)
    - `weekly`: `{ startDate, quantity, dayOfWeek }` (`dayOfWeek`: `SEGUNDA_FEIRA` … `DOMINGO`)
    - `monthly`: `{ startDate, quantity, dayOfMonth }`
    - `custom`: `{ dates: string[], additionalInformation? }`

**Retorna:** `Promise<PaymentRequestData>` com:

- `id` (string): identificador da solicitação
- `redirectUri` (string): URI para seguir o fluxo de autorização/pagamento

**Erros:** falhas de validação do payload resultam em `LinaPayError` com a mensagem `Invalid payload`. Erros HTTP e de rede seguem o mesmo padrão dos demais métodos do SDK.

**Exemplo:**

```typescript
import {
  createPaymentRequest,
  type CreatePaymentRequestDTO,
  type PaymentRequestData,
} from '@lina-openx/web-lina-pay-sdk'

const result: PaymentRequestData = await createPaymentRequest(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret',
  },
  {
    details: 'Pagamento de serviço',
    redirectUri: 'https://exemplo.com/retorno',
    cpfCnpj: '12345678901',
    value: 150.5,
    creditor: {
      name: 'Maria Souza',
      personType: 'PESSOA_NATURAL',
      cpfCnpj: '98765432100',
      accountNumber: '12345-6',
      accountIssuer: '0001',
      accountPixKey: 'maria@exemplo.com',
      accountIspb: '12345678',
      accountType: 'CACC',
    },
    schedule: {},
  } satisfies CreatePaymentRequestDTO,
)

console.log('ID da solicitação:', result.id)
console.log('Redirect:', result.redirectUri)
```

**Exemplo com `txId` e agendamento único:**

```typescript
await createPaymentRequest(credentials, {
  details: 'Pagamento agendado',
  txId: 'E123456782024...',
  redirectUri: 'https://exemplo.com/callback',
  cpfCnpj: '12345678901',
  value: 200,
  creditor: {
    /* ... */
  },
  schedule: {
    single: { date: '2026-02-15' },
  },
})
```

---

### 5. `getPaymentRequest(credentials, id)`

Consulta os **detalhes de uma solicitação de pagamento** já criada. O SDK chama `GET` no endpoint de payment requests (`…/requests/:id`) com o token obtido automaticamente a partir das credenciais do subtenant.

**Parâmetros:**

- `credentials`: objeto `LinaPayCredentials` (`subtenantId`, `subtenantSecret`)
- `id` (string): identificador da solicitação — em geral o mesmo `id` retornado por `createPaymentRequest`

**Retorna:** `Promise<PaymentRequestData>` com o corpo `data` da API (sem o envelope `message` / `type`). Em respostas completas da API você pode esperar campos como:

- `id`, `redirectUri`, `tenantId`
- `status`, `type`, `value`
- `createDateTime`, `lastChangedDateTime`, `requestExpiresAt` (quando aplicável)
- `cpfCnpj`, `consentId`, `externalId`, `externalComment`, `businessCnpj` (quando aplicável)
- `creditor` e `debitor` com dados da conta
- `payments`: lista de itens/parcelas associados à solicitação

O formato exato segue o tipo `PaymentRequestData` exportado pelo pacote (alinhado ao contrato da API).

**Erros:** respostas HTTP de erro e falhas de rede propagam `LinaPayError`, como nos demais métodos.

**Exemplo:**

```typescript
import { createPaymentRequest, getPaymentRequest } from '@lina-openx/web-lina-pay-sdk'

const { id } = await createPaymentRequest(credentials, payload)

const details = await getPaymentRequest(credentials, id)

console.log('Status:', details.status)
console.log('Valor:', details.value)
console.log('Redirect:', details.redirectUri)
```

---

### 6. `createEnrollment(credentials, payload)`

Cria um enrollment (cadastro de dispositivo) para pagamentos recorrentes com autenticação FIDO2.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `payload`: Objeto `CreateEnrollmentRequest` com:
  - `organisationId` (string): ID da organização
  - `authorisationServerId` (string): ID do servidor de autorização
  - `enrollment` (objeto): Detalhes do enrollment
  - `redirectUri` (string): URI de redirecionamento
  - `paymentId` (string, opcional): ID do pagamento relacionado

**Retorna:** `Promise<CreateEnrollmentResponse>` com `consentId` e `redirectUrl`

**Exemplo:**
```typescript
const enrollment = await createEnrollment(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  {
    organisationId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    authorisationServerId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    enrollment: {
      deviceName: 'Meu Dispositivo',
      document: '12345678901', // CPF sem formatação
      debtor: {
        accountIspb: '00000000',
        accountIssuer: '2558',
        accountNumber: '5271110',
        accountType: 'CACC'
      }
    },
    redirectUri: 'https://exemplo.com/redirect'
  }
)

console.log('Enrollment Consent ID:', enrollment.consentId)
```

---

### 7. `registerDevice(credentials, payload)`

Registra um dispositivo após o callback do enrollment, validando e processando o registro FIDO2.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `payload`: Objeto `RegisterDeviceRequest` com:
  - `state` (string): Estado do fluxo OAuth
  - `code` (string): Código de autorização
  - `idToken` (string): Token de identificação
  - `tenantId` (string): ID do tenant
  - `platform` (string): Plataforma ('ANDROID' | 'IOS' | 'WEB' | 'BROWSER' | 'CROSS_PLATFORM')
  - `rp` (string, opcional): Relying Party identifier

**Retorna:** `Promise<Enrollment>` com detalhes do enrollment registrado

**Exemplo:**
```typescript
const enrollment = await registerDevice(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  {
    state: 'rumUP',
    code: '1RDYVFQnPn721',
    idToken: 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...',
    tenantId: 'tenant-id-123',
    platform: 'WEB'
  }
)

console.log('Enrollment ID:', enrollment.id)
console.log('Device Name:', enrollment.deviceName)
```

---

### 8. `getEnrollmentList(credentials, cpf)`

Obtém a lista de enrollments registrados para um CPF.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `cpf` (string): CPF do usuário (com ou sem formatação)

**Retorna:** `Promise<EnrollmentList>` com array de enrollments

**Exemplo:**
```typescript
const enrollments = await getEnrollmentList(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  '12345678901'
)

console.log('Total de enrollments:', enrollments.length)
enrollments.forEach(enrollment => {
  console.log(`- ${enrollment.deviceName} (ID: ${enrollment.id})`)
})
```

---

### 9. `revokeEnrollment(credentials, enrollmentId)`

Revoga (remove) um enrollment específico.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `enrollmentId` (string): ID do enrollment a ser revogado

**Retorna:** `Promise<RevokeEnrollmentResponse>` com status da revogação

**Exemplo:**
```typescript
const result = await revokeEnrollment(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  '1728979312391739'
)

console.log('Enrollment revogado com sucesso')
```

---

### 10. `createPaymentWithEnrollment(credentials, payload)`

Cria um pagamento usando um enrollment existente (pagamento recorrente com autenticação FIDO2).

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant
- `payload`: Objeto `PaymentWithEnrollmentRequest` com:
  - `enrollmentId` (string): ID do enrollment
  - `organisationId` (string): ID da organização
  - `authorisationServerId` (string): ID do servidor de autorização
  - `payment` (objeto): Detalhes do pagamento
  - `fidoSignOptions` (objeto): Opções de assinatura FIDO2
  - `paymentId` (string, opcional): ID do pagamento relacionado

**Retorna:** `Promise<RetornoJsrPaymentDto>` com detalhes do pagamento criado

**Exemplo:**
```typescript
const payment = await createPaymentWithEnrollment(
  {
    subtenantId: 'seu-subtenant-id',
    subtenantSecret: 'seu-subtenant-secret'
  },
  {
    enrollmentId: 'enrollment-id-123',
    organisationId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    authorisationServerId: 'c8f0bf49-4744-4933-8960-7add6e590841',
    payment: {
      redirectUri: 'https://exemplo.com/redirect',
      value: 1500.50,
      creditor: {
        name: 'João Silva',
        personType: 'PESSOA_NATURAL',
        cpfCnpj: '12345678901',
        accountNumber: '12345-6',
        accountIssuer: '0001',
        accountPixKey: 'joao@exemplo.com',
        accountIspb: '12345678',
        accountType: 'CACC'
      }
    },
    fidoSignOptions: {
      rp: 'relying-party-id',
      platform: 'WEB'
    }
  }
)

console.log('Payment ID:', payment.id)
console.log('Status:', payment.status)
```

---

### 11. `getParticipants(credentials)`

Obtém a lista de participantes (bancos) registrados na plataforma Lina Open Finance.

**Parâmetros:**
- `credentials`: Objeto com credenciais do subtenant

**Retorna:** `Promise<Participant[]>` com array de participantes

**Exemplo:**
```typescript
const participants = await getParticipants({
  subtenantId: 'seu-subtenant-id',
  subtenantSecret: 'seu-subtenant-secret'
})

console.log('Participantes disponíveis:')
participants.forEach(participant => {
  console.log(`- ${participant.name} (ISPB: ${participant.ispb})`)
})
```

---

## 🏗️ Organização de Pastas

```
src/
├── config/              # Configurações do SDK
│   └── environment.ts  # Configuração de URLs e endpoints
├── controllers/        # Controllers públicos (API do SDK)
│   ├── config.controller.ts
│   ├── consent.controller.ts
│   ├── enrollment.controller.ts
│   ├── participants.controller.ts
│   ├── payment.controller.ts
│   └── tests/          # Testes unitários dos controllers
├── services/           # Serviços de comunicação com APIs
│   ├── auth.service.ts
│   ├── consent.service.ts
│   ├── enrollment.service.ts
│   ├── fido.service.ts
│   ├── participants.service.ts
│   ├── payment.service.ts
│   └── tests/          # Testes unitários dos services
├── types/              # Definições de tipos TypeScript
│   ├── auth.types.ts
│   ├── consent.types.ts
│   ├── enrollment.types.ts
│   ├── fido.types.ts
│   ├── index.ts
│   ├── participants.types.ts
│   └── payment.types.ts
├── utils/              # Utilitários e validações
│   ├── consent.utils.ts
│   ├── enrollment.utils.ts
│   ├── error-handling.utils.ts
│   ├── payment.utils.ts
│   ├── validate-credentials.utils.ts
│   └── tests/          # Testes unitários dos utils
└── index.ts            # Ponto de entrada principal
```

### Descrição das Pastas

- **`config/`**: Contém configurações globais do SDK, como URLs base e endpoints da API
- **`controllers/`**: Camada pública do SDK, expondo métodos que os desenvolvedores utilizam
- **`services/`**: Camada de comunicação com as APIs externas, lidando com requisições HTTP
- **`types/`**: Definições TypeScript para type-safety em todo o SDK
- **`utils/`**: Funções utilitárias para validação, tratamento de erros e outras operações auxiliares
- **`tests/`**: Testes unitários organizados por módulo

---

## 🛠️ Como Rodar Localmente

### Pré-requisitos

- Node.js 18+ 
- npm, yarn ou pnpm

### Instalação das Dependências

```bash
npm install
```

### Scripts Disponíveis

```bash
# Executar testes em modo watch
npm run dev

# Executar todos os testes
npm run test

# Formatar código
npm run format

# Build do projeto
npm run build

# Executar CI completo (build + lint + test)
npm run ci
```

### Desenvolvimento

1. Clone o repositório:
```bash
git clone git@gitlab.com:lina-infratech/ob-data-pull/web-lina-pay-sdk.git
cd web-lina-pay-sdk
```

2. Instale as dependências:
```bash
npm install
```

3. Execute os testes para verificar se tudo está funcionando:
```bash
npm run test
```

4. Para desenvolvimento com watch mode:
```bash
npm run dev
```

5. Para build do projeto:
```bash
npm run build
```

O build gerará os arquivos compilados na pasta `dist/`.

### Exemplo de Uso Local

Você pode testar o SDK localmente usando o projeto de exemplo na pasta `example/`:

```bash
cd example
npm install
npm run dev
```

---

## ⚠️ Tratamento de Erros

O SDK lança `LinaPayError` para erros de validação e comunicação. Sempre use try/catch ao chamar os métodos:

```typescript
import { createConsent, LinaPayError } from '@lina-openx/web-lina-pay-sdk'

try {
  const consent = await createConsent(credentials, payload)
  console.log('Sucesso:', consent.consentId)
} catch (error) {
  if (error instanceof LinaPayError) {
    console.error('Erro do SDK:', error.message)
    console.error('Status Code:', error.statusCode)
  } else {
    console.error('Erro inesperado:', error)
  }
}
```

---

## 📝 Tipos Principais

### LinaPayCredentials
```typescript
interface LinaPayCredentials {
  subtenantId: string
  subtenantSecret: string
}
```

### CreateConsentRequest
```typescript
interface CreateConsentRequest {
  organisationId: string
  authorisationServerId: string
  payment: Payment
  redirectUri?: string
  platform?: 'APP' | 'WEB'
}
```

### CreatePayment
Payload do método `createPayment` (callback OAuth após consentimento).

```typescript
interface CreatePayment {
  state: string
  code: string
  idToken: string
  tenantId: string
}
```

### CreatePaymentRequestDTO
Payload do método `createPaymentRequest` (solicitação de pagamento). O runtime valida com Zod; campos de `schedule` seguem as regras descritas na seção desse método.

```typescript
interface CreatePaymentRequestDTO {
  details: string
  txId?: string | string[]
  externalId?: string
  redirectUri: string
  cpfCnpj: string
  value: number
  creditor: Creditor
  schedule?: { /* single | daily | weekly | monthly | custom — ver documentação */ }
}
```

### PaymentRequestData
Usado como retorno de `createPaymentRequest` (campos mínimos típicos: `id`, `redirectUri`) e de `getPaymentRequest` (objeto detalhado retornado pela API ao consultar `GET …/requests/:id`). O tipo exportado reflete o contrato completo da consulta; na criação, a API pode devolver apenas um subconjunto dos campos.

```typescript
// Visão resumida — ver `src/types/payment.types.ts` para o tipo completo exportado
interface PaymentRequestData {
  id: string
  redirectUri: string
  // Em getPaymentRequest: status, value, creditor, debitor, payments, datas, tenantId, consentId, etc.
}
```

Para mais tipos, consulte os arquivos em `src/types/`.

---

## 📄 Licença

MIT

---

## 🤝 Suporte

Para suporte, entre em contato:
- Email: suporte@linaopenx.com.br
- Website: https://www.linaopenx.com.br/
- Issues: https://gitlab.com/lina-infratech/ob-data-pull/web-lina-pay-sdk/issues