196 lines
7.5 KiB
Markdown
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.
|