agendapro/asaas_skill.md

196 lines
7.5 KiB
Markdown

# Integração Asaas Payment Gateway - AgendaPRO
Este documento serve como guia técnico ("Skill") para a integração do gateway de pagamento **Asaas** na plataforma SaaS multi-tenant **AgendaPRO**. Ele detalha os fluxos de trabalho, estruturas de API, segurança do Webhook e regras de conciliação financeira em banco de dados PostgreSQL.
---
## 1. Visão Geral da Arquitetura
A integração é baseada no modelo **SQL-First**, onde o banco de dados PostgreSQL é a única fonte da verdade. O mapeamento é feito associando os IDs internos do sistema (`UUID`) ao campo `externalReference` fornecido pela API do Asaas.
```mermaid
sequenceDiagram
participant Cliente/Tenant as App/Painel (AgendaPRO)
participant Lib as Serviço Asaas (src/lib/asaas.ts)
participant Asaas as Asaas API (Sandbox/Prod)
participant DB as PostgreSQL
Cliente/Tenant->>Lib: Solicita Cobrança/Assinatura
Lib->>DB: Busca Configuração do Tenant (API Key)
DB-->>Lib: Retorna Configuração do Tenant
Lib->>Asaas: POST /v3/payments (ou /subscriptions) com externalReference
Asaas-->>Lib: Retorna Dados da Transação (ID do Asaas)
Lib-->>Cliente/Tenant: Retorna Link/QR Code Pix para o Cliente
```
---
## 2. Ambientes e Autenticação
O Asaas possui dois ambientes distintos. As chaves de API (`API Keys`) geradas no Sandbox não funcionam em Produção e vice-versa.
| Ambiente | URL Base da API v3 | Variável de Ambiente |
| :--- | :--- | :--- |
| **Sandbox (Homologação)** | `https://api-sandbox.asaas.com/v3` | `ASAAS_API_KEY` (Prefixo de teste) |
| **Produção** | `https://api.asaas.com/v3` | `ASAAS_API_KEY` |
### Cabeçalhos HTTP Obrigatórios
Todas as chamadas à API devem conter:
* `access_token`: Sua chave de API do Asaas (específica para o tenant ou plataforma).
* `Content-Type`: `application/json`.
* `User-Agent`: Nome da aplicação (ex: `AgendaPRO-Integration`).
---
## 3. Fluxo de Clientes (Customers)
Antes de emitir qualquer cobrança ou assinatura, o cliente (consumidor final) deve ser cadastrado no Asaas. O ID do cliente retornado (`cus_...`) deve ser salvo no banco local (ex: no cadastro de inquilino/tenant ou no cadastro de cliente do estabelecimento).
* **Endpoint:** `POST /v3/customers`
* **Payload Exemplo:**
```json
{
"name": "João Mendes",
"cpfCnpj": "00000000000",
"email": "joao@email.com",
"phone": "11999991234",
"mobilePhone": "11999991234",
"externalReference": "local-client-uuid",
"notificationDisabled": false
}
```
* **Response de Sucesso:** Retorna o objeto do cliente contendo o `"id": "cus_000005219613"`.
---
## 4. Fluxo de Cobranças Avulsas (Payments - Pix/Boleto/Cartão)
Usado para pagamentos individuais, como a cobrança por um agendamento específico.
* **Endpoint:** `POST /v3/payments`
* **Payload Exemplo (Pix/Boleto):**
```json
{
"customer": "cus_000005219613",
"billingType": "PIX",
"value": 55.00,
"dueDate": "2026-06-10",
"description": "Corte Masculino - Barbearia Premium",
"externalReference": "local-payment-uuid"
}
```
* **Response de Sucesso:** Retorna o ID da transação (ex: `"id": "pay_080225913252"`).
### Obtenção do QR Code Dinâmico Pix
Se a cobrança for do tipo `PIX`, você pode buscar a imagem em Base64 e a linha digitável ("copia e cola"):
* **Endpoint:** `GET /v3/payments/{id}/pixQrCode` (Sem corpo na requisição)
* **Response Exemplo:**
```json
{
"encodedImage": "iVBORw0KGgoAAAANSUhEUgAA...",
"payload": "00020101021126660014br.gov.bcb.pix...",
"expirationDate": "2026-06-10T23:59:59Z"
}
```
---
## 5. Fluxo de Assinaturas Recorrentes (Subscriptions)
Usado pelo SaaS para cobrar a mensalidade do próprio inquilino (Tenant) ou pelos inquilinos para oferecer planos recorrentes.
* **Endpoint:** `POST /v3/subscriptions`
* **Payload Exemplo (Cartão de Crédito):**
```json
{
"customer": "cus_0T1mdomVMi39",
"billingType": "CREDIT_CARD",
"nextDueDate": "2026-07-03",
"value": 99.90,
"cycle": "MONTHLY",
"description": "Assinatura AgendaPRO - Plano Professional",
"externalReference": "local-subscription-uuid",
"creditCard": {
"holderName": "TITULAR DO CARTAO",
"number": "0000000000000000",
"expiryMonth": "12",
"expiryYear": "2030",
"ccv": "123"
},
"creditCardHolderInfo": {
"name": "TITULAR DO CARTAO",
"email": "titular@email.com",
"cpfCnpj": "00000000000",
"postalCode": "01310000",
"addressNumber": "123",
"phone": "11999991234"
}
}
```
---
## 6. Webhook e Segurança
O webhook do Asaas garante a conciliação automática do status de pagamentos de forma assíncrona.
### Validação de Autenticidade (Signature)
Diferente de gateways que usam assinaturas HMAC, o Asaas utiliza um **Token de Acesso Simples** configurado na interface do webhook.
1. Configure um Token Secreto no Painel do Asaas (ou salve em `settings` no banco local do tenant).
2. O Asaas enviará este token no cabeçalho `asaas-access-token` em cada requisição de Webhook.
3. A aplicação deve validar: `req.headers.get('asaas-access-token') === webhookSecret`.
### Estrutura de Payload do Webhook
```json
{
"id": "evt_05b708f961d739ea7eba7e4db318f621",
"event": "PAYMENT_RECEIVED",
"dateCreated": "2026-06-03 20:20:00",
"payment": {
"id": "pay_080225913252",
"customer": "cus_000005219613",
"subscription": "sub_VXJBYgP2u0eO",
"value": 100.00,
"netValue": 95.00,
"externalReference": "local-payment-uuid",
"billingType": "PIX",
"confirmedDate": "2026-06-03"
}
}
```
### Eventos Críticos a Processar
* `PAYMENT_RECEIVED` / `PAYMENT_CONFIRMED`: Pagamento efetuado com sucesso.
* `PAYMENT_REFUNDED`: Pagamento estornado pelo painel ou pelo banco.
* `PAYMENT_OVERDUE`: Vencimento expirado sem quitação.
* `PAYMENT_DELETED`: Cobrança removida manualmente.
* `SUBSCRIPTION_DELETED` / `SUBSCRIPTION_CANCELLED`: Cancelamento de recorrência.
---
## 7. Estrutura do Código Implementado
### A. Camada de Serviço (`src/lib/asaas.ts`)
Fornece funções isoladas e parametrizadas que realizam as chamadas seguras para a API, respeitando a separação de chaves por inquilino (`tenant_id`).
### B. Handler de Webhook (`src/app/api/webhooks/asaas/route.ts`)
Endpoint público que recebe requisições do Asaas. Executa os seguintes passos:
1. Valida o token `asaas-access-token` contra o token do Tenant (se enviado com `?tenant_id=...`) ou contra o token mestre do sistema.
2. Cria e utiliza a tabela `asaas_webhook_events` para garantir **idempotência** (ignora eventos duplicados).
3. Atualiza o status financeiro local em uma transação segura (`BEGIN/COMMIT`).
---
## 8. Guia de Teste no Sandbox
1. **Configuração de Chaves:**
* Vá em [Asaas Sandbox](https://sandbox.asaas.com/) > Minha Conta > Integrações.
* Gere uma chave de API e insira o webhook apontando para a sua URL pública exposta pelo Ngrok/Cloudflare Tunnel (ex: `https://seu-dominio.trycloudflare.com/api/webhooks/asaas?tenant_id=UUID-DO-TENANT`).
2. **Simulação de Pagamentos:**
* Crie uma cobrança do tipo Pix/Boleto pela API.
* Acesse o painel de Sandbox do Asaas.
* Procure a cobrança emitida e clique em **Confirmar Recebimento** (Botão de teste que simula o pagamento do cliente).
3. **Validação de Banco de Dados:**
* Execute: `SELECT status, paid_at FROM payments WHERE id = 'seu-uuid';`
* Verifique se o status mudou para `completed` e a coluna `paid_at` foi preenchida corretamente.