skill-cobranca-automatizada-saas-abacatepay
When To Use
This skill covers the complete automated billing system ("cobranca automatizada") for Brazilian SaaS products using AbacatePay. Use when implementing or maintaining:
=== Provisioning ===
- Billing configuration tables (cobrancas, cobranca_reguas, billing_config, etc.)
- Dunning rule sequencing (cobranca_regua_eventos)
- Encrypted integration configs (Resend, Evolution API, AbacatePay)
=== Billing Engine ===
- Automated invoice generation and dunning execution via cron
- AbacatePay billing creation (PIX + CARD)
- Webhook processing with HMAC-SHA256 verification
- Invoice state machine (pending, paid, overdue, cancelled, refunded)
- Subscription/plan integration via cobranca_tracking
=== Trial Management ===
- Configurable trial duration
- Pre-expiration notifications (7/3/1 days before)
- Automatic trial expiration and account blocking
=== Interfaces ===
- Public invoice page (FaturaPage) with PIX QR Code, payment link, polling
- Pricing/Plans page with AbacatePay checkout
- User-side invoice listing (MinhasCobrancasSection)
- Admin billing management (cobranças CRUD, planos CRUD, global settings)
- Plan Manager (PlanManager) for user plan changes
=== Notifications ===
- Email via Resend with HTML templates (logo, badge, invoice details)
- WhatsApp via Evolution API with template variables
- Variables: {{nome}}, {{plano}}, {{valor}}, {{vencimento}}, {{link_pagamento}}, {{empresa_nome}}
- Dunning sequence: configurable events with days_apos_vencimento, channel (email/whatsapp/ambos)
Architecture
+-------------------+
| Cron (8/12/16h |
| BRT + 5min) |
+--------+----------+
|
+--------------------+--------------------+
| | |
Processar Trial Metrics
Cobranças Notificações (meia-noite)
| |
+-----v------+ +-----v------+
| Ver regua | | Trial exp. |
| Send notif | | Notif pre |
| Create bill | +------------+
+-----+------+
|
+-----v------------------------------------------+
| Controller Layer |
| cobrancas.ts | abacatepay-webhook.ts |
| fatura.ts | trial.ts |
+-----+----------------------------+--------------+
| |
+-----v----------+ +--------v---------+
| AbacatePay | | Notifications |
| API v2 | | Resend + Evol. |
+----------------+ +------------------+
|
+-----v----------+
| Supabase/ |
| PostgreSQL |
+----------------+
Billing State Machine
pending ──► paid ──► refunded
│
├──► overdue ──► paid
│ └──► cancelled
│
└──► cancelled
States managed by invoice-state-machine.ts:
pending: cobrança criada, aguardando pagamento
paid: paga, released_at setado, conteúdo liberado
overdue: vencida, entra na régua de cobrança
cancelled: cancelada manualmente ou por expiração
refunded: estornada (transição exclusiva de paid)
Key Tables
| Table |
Purpose |
cobrancas |
Core billing records per user |
cobranca_reguas |
Dunning rule sets per tenant |
cobranca_regua_eventos |
Individual dunning events in sequence |
billing_config |
Encrypted integration configs (Resend, Evolution, AbacatePay) |
front_users |
User profiles with plan and status |
partner_billing_config |
Partner-specific billing overrides |
cobranca_tracking |
Subscription-like recurring billing tracking |
transaction_log |
Billing operation audit log |
abacatepay_events |
Raw webhook event storage |
Full details in billing-tables.md.
Core Flows
Dunning Flow (Régua de Cobrança)
- Cron runs billing-cron.ts at 8h/12h/16h BRT
- Queries cobrancas WHERE status = 'overdue' AND NOT paga
- For each cobranca, resolves billing_config + cobranca_regua + cobranca_regua_eventos
- Checks if next evento should fire (based on dias_apos_vencimento)
- Sends notification via billing-sender.ts (email + WhatsApp)
- If all eventos fired and still overdue, marks as cancelled
Webhook Flow
- POST /api/abacatepay-webhook receives an AbacatePay v2 event
- HMAC-SHA256 signature verification (replay + timing-safe compare)
- Rate limited: 100 req/min per IP
- On
checkout.completed or subscription.renewed: processPaymentWithTransaction updates cobranca + cobranca_tracking
- On failure: processRollback reverts state
- Raw event stored in abacatepay_events
Trial Flow
- trial-cron.ts runs every 5 minutes
- Queries users where trial ends within notification window
- Sends pre-expiration notifications (7/3/1 day before)
- On expiration: blocks account (status = blocked)
- billing-cron.ts also handles trial notifications at 8/12/16h
Invoice Portal Flow
- FaturaPage loads by shortlink (8 chars, unique)
- Materializes billing from AbacatePay API on demand
- Shows: PIX QR Code, payment link, due date, amount, status badge
- Polls status every 5 seconds
- "Share via WhatsApp" button with pre-formatted message
Configuration
billing_config stores encrypted credentials per owner (AES-256-GCM):
resend_config: Resend API key + from email
evolution_config: Evolution API URL + API key + instance
abacatepay_config: AbacatePay API key
trial_duration_days: Trial length (default)
- Encryption key: BILLING_CONFIG_ENCRYPTION_KEY env var
See billing-config.md for full schema and setup.
Provider API Boundary
- AbacatePay: new code uses API v2 and the webhook events
checkout.completed, checkout.refunded, checkout.disputed, subscription.completed, subscription.renewed, and subscription.cancelled. The legacy v1 billing.* events belong behind a migration adapter.
- Resend: keep the key server-side and send through the official SDK or
POST https://api.resend.com/emails with Authorization: Bearer <key> and a User-Agent; use Idempotency-Key for retryable sends, record provider request IDs, and redact message content from logs.
- Evolution API: use the deployed v2 documentation and
apikey header; keep instance credentials server-side and account for v2.4.0 activation/licensing before diagnosing business-endpoint failures.
Guardrails
- Keep ALL payment provider secrets server-side. Never expose AbacatePay API keys in browser bundles.
- Process webhooks idempotently: check cobranca current state before mutating.
- Treat checkout redirect as advisory. Grant access only after webhook confirmation.
- Do not log API keys, webhook secrets, full CPF/CNPJ, full phone numbers.
- Cron must not overlap. billing-cron uses lock checks to prevent concurrent runs.
- Dunning notifications must respect channel preference (email, whatsapp, or ambos).
- Trial expiration is irreversible: set status = blocked, do not auto-unblock without payment.
- Metrics queries (MRR, faturamento) should use aggregateBillingMetrics(), not ad-hoc SQL.
- New integrations must use
https://api.abacatepay.com/v2, /checkouts/create, /subscriptions/create, and /transparents/create as appropriate. Keep /v1/billing/* and billing.* only inside an explicit legacy adapter.
Local Reference (example-saas)
This skill is extracted from the example-saas SaaS billing system. The production codebase is at:
{{USER_HOME}}/Documents/Code/example-saas/server/controllers/cobrancas.ts — billing CRUD + processing + dunning
{{USER_HOME}}/Documents/Code/example-saas/server/controllers/abacatepay-webhook.ts — webhook handler
{{USER_HOME}}/Documents/Code/example-saas/server/controllers/fatura.ts — invoice lookup by shortlink
{{USER_HOME}}/Documents/Code/example-saas/server/controllers/trial.ts — trial expiration processing
{{USER_HOME}}/Documents/Code/example-saas/server/services/abacatepay-create-billing-v2.ts — AbacatePay billing creation
{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-sender.ts — notification dispatch (email + WhatsApp)
{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-email-template.ts — HTML invoice email template
{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-integrations-config.ts — encrypted config management
{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-metrics.ts — MRR and billing metrics
{{USER_HOME}}/Documents/Code/example-saas/server/utils/invoice-state-machine.ts — state machine logic
{{USER_HOME}}/Documents/Code/example-saas/server/cron/billing-cron.ts — main billing scheduler
{{USER_HOME}}/Documents/Code/example-saas/server/cron/trial-cron.ts — trial scheduler
{{USER_HOME}}/Documents/Code/example-saas/src/pages/FaturaPage.tsx — public invoice page
{{USER_HOME}}/Documents/Code/example-saas/src/components/PlansPage.tsx — pricing/plans page
{{USER_HOME}}/Documents/Code/example-saas/src/components/PlanManager.tsx — user plan manager
{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminCobrancas.tsx — admin billing CRUD
{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminPlanos.tsx — admin plan CRUD
{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminGlobalSettings.tsx — global settings
{{USER_HOME}}/Documents/Code/example-saas/src/components/MinhasCobrancasSection.tsx — user invoice list
{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20260617_cobrancas_foundation.sql — core tables
{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20260617_cobrancas_website_final.sql — shortlink trigger
{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20240101_billing_config.sql — billing_config table
{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20240117_partner_billing.sql — partner billing
Reference Files
billing-tables.md — complete table schemas, indexes, enums, RLS policies
billing-flows.md — detailed flow diagrams and pseudocode for each core flow
billing-config.md — encryption, config resolution, and setup steps
billing-admin.md — admin interfaces and CRUD operations
billing-notifications.md — email/WhatsApp templates, dunning sequence, template variables
Validation
- After changes, run build and typecheck (npm run build, npm run typecheck or equivalent)
- Simulate webhook: POST
checkout.completed and subscription.renewed events and verify idempotent processing
- Test dunning: create overdue cobranca with regua de 0/3/7 dias and confirm notification dispatch
- Test trial: set trial_duration_days=1, create user, wait for pre-expiration and expiration
- Verify no AbacatePay/Resend/Evolution keys leak to browser bundles
- Run project lint when available
Related Skills
skill-abacatepay-integration — AbacatePay v2 API specifics and legacy v1 migration boundary
skill-saas-core-limits — plan limits, entitlements, feature flags after payment
skill-evolution-api — WhatsApp notification channel
skill-supabase-rls — RLS policies for billing tables
skill-saas-factory — top-level SaaS construction entry
1---2name: skill-cobranca-automatizada-saas-abacatepay3description: Automatic SaaS billing engine with AbacatePay (PIX + credit card), configurable dunning (regua de cobranca), trial management, invoice portal, email (Resend) and WhatsApp (Evolution API) notifications, admin CRUD, and billing metrics. Covers the full billing lifecycle from provisioning to collection.4---56# skill-cobranca-automatizada-saas-abacatepay78## When To Use910This skill covers the complete automated billing system ("cobranca automatizada") for Brazilian SaaS products using AbacatePay. Use when implementing or maintaining:1112=== Provisioning ===13- Billing configuration tables (cobrancas, cobranca_reguas, billing_config, etc.)14- Dunning rule sequencing (cobranca_regua_eventos)15- Encrypted integration configs (Resend, Evolution API, AbacatePay)1617=== Billing Engine ===18- Automated invoice generation and dunning execution via cron19- AbacatePay billing creation (PIX + CARD)20- Webhook processing with HMAC-SHA256 verification21- Invoice state machine (pending, paid, overdue, cancelled, refunded)22- Subscription/plan integration via cobranca_tracking2324=== Trial Management ===25- Configurable trial duration26- Pre-expiration notifications (7/3/1 days before)27- Automatic trial expiration and account blocking2829=== Interfaces ===30- Public invoice page (FaturaPage) with PIX QR Code, payment link, polling31- Pricing/Plans page with AbacatePay checkout32- User-side invoice listing (MinhasCobrancasSection)33- Admin billing management (cobranças CRUD, planos CRUD, global settings)34- Plan Manager (PlanManager) for user plan changes3536=== Notifications ===37- Email via Resend with HTML templates (logo, badge, invoice details)38- WhatsApp via Evolution API with template variables39- Variables: {{nome}}, {{plano}}, {{valor}}, {{vencimento}}, {{link_pagamento}}, {{empresa_nome}}40- Dunning sequence: configurable events with days_apos_vencimento, channel (email/whatsapp/ambos)4142## Architecture4344```45 +-------------------+46 | Cron (8/12/16h |47 | BRT + 5min) |48 +--------+----------+49 |50 +--------------------+--------------------+51 | | |52 Processar Trial Metrics53 Cobranças Notificações (meia-noite)54 | |55 +-----v------+ +-----v------+56 | Ver regua | | Trial exp. |57 | Send notif | | Notif pre |58 | Create bill | +------------+59 +-----+------+60 |61 +-----v------------------------------------------+62 | Controller Layer |63 | cobrancas.ts | abacatepay-webhook.ts |64 | fatura.ts | trial.ts |65 +-----+----------------------------+--------------+66 | |67 +-----v----------+ +--------v---------+68 | AbacatePay | | Notifications |69 | API v2 | | Resend + Evol. |70 +----------------+ +------------------+71 |72 +-----v----------+73 | Supabase/ |74 | PostgreSQL |75 +----------------+76```7778## Billing State Machine7980```81pending ──► paid ──► refunded82 │83 ├──► overdue ──► paid84 │ └──► cancelled85 │86 └──► cancelled87```8889States managed by `invoice-state-machine.ts`:90- `pending`: cobrança criada, aguardando pagamento91- `paid`: paga, `released_at` setado, conteúdo liberado92- `overdue`: vencida, entra na régua de cobrança93- `cancelled`: cancelada manualmente ou por expiração94- `refunded`: estornada (transição exclusiva de `paid`)9596## Key Tables9798| Table | Purpose |99|---|---|100| `cobrancas` | Core billing records per user |101| `cobranca_reguas` | Dunning rule sets per tenant |102| `cobranca_regua_eventos` | Individual dunning events in sequence |103| `billing_config` | Encrypted integration configs (Resend, Evolution, AbacatePay) |104| `front_users` | User profiles with plan and status |105| `partner_billing_config` | Partner-specific billing overrides |106| `cobranca_tracking` | Subscription-like recurring billing tracking |107| `transaction_log` | Billing operation audit log |108| `abacatepay_events` | Raw webhook event storage |109110Full details in `billing-tables.md`.111112## Core Flows113114### Dunning Flow (Régua de Cobrança)1151. Cron runs billing-cron.ts at 8h/12h/16h BRT1162. Queries cobrancas WHERE status = 'overdue' AND NOT paga1173. For each cobranca, resolves billing_config + cobranca_regua + cobranca_regua_eventos1184. Checks if next evento should fire (based on dias_apos_vencimento)1195. Sends notification via billing-sender.ts (email + WhatsApp)1206. If all eventos fired and still overdue, marks as cancelled121122### Webhook Flow1231. POST /api/abacatepay-webhook receives an AbacatePay v2 event1242. HMAC-SHA256 signature verification (replay + timing-safe compare)1253. Rate limited: 100 req/min per IP1264. On `checkout.completed` or `subscription.renewed`: processPaymentWithTransaction updates cobranca + cobranca_tracking1275. On failure: processRollback reverts state1286. Raw event stored in abacatepay_events129130### Trial Flow1311. trial-cron.ts runs every 5 minutes1322. Queries users where trial ends within notification window1333. Sends pre-expiration notifications (7/3/1 day before)1344. On expiration: blocks account (status = blocked)1355. billing-cron.ts also handles trial notifications at 8/12/16h136137### Invoice Portal Flow1381. FaturaPage loads by shortlink (8 chars, unique)1392. Materializes billing from AbacatePay API on demand1403. Shows: PIX QR Code, payment link, due date, amount, status badge1414. Polls status every 5 seconds1425. "Share via WhatsApp" button with pre-formatted message143144## Configuration145146billing_config stores encrypted credentials per owner (AES-256-GCM):147- `resend_config`: Resend API key + from email148- `evolution_config`: Evolution API URL + API key + instance149- `abacatepay_config`: AbacatePay API key150- `trial_duration_days`: Trial length (default)151- Encryption key: BILLING_CONFIG_ENCRYPTION_KEY env var152153See `billing-config.md` for full schema and setup.154155## Provider API Boundary156157- AbacatePay: new code uses API v2 and the webhook events `checkout.completed`, `checkout.refunded`, `checkout.disputed`, `subscription.completed`, `subscription.renewed`, and `subscription.cancelled`. The legacy v1 `billing.*` events belong behind a migration adapter.158- Resend: keep the key server-side and send through the official SDK or `POST https://api.resend.com/emails` with `Authorization: Bearer <key>` and a `User-Agent`; use `Idempotency-Key` for retryable sends, record provider request IDs, and redact message content from logs.159- Evolution API: use the deployed v2 documentation and `apikey` header; keep instance credentials server-side and account for v2.4.0 activation/licensing before diagnosing business-endpoint failures.160161## Guardrails1621631. Keep ALL payment provider secrets server-side. Never expose AbacatePay API keys in browser bundles.1642. Process webhooks idempotently: check cobranca current state before mutating.1653. Treat checkout redirect as advisory. Grant access only after webhook confirmation.1664. Do not log API keys, webhook secrets, full CPF/CNPJ, full phone numbers.1675. Cron must not overlap. billing-cron uses lock checks to prevent concurrent runs.1686. Dunning notifications must respect channel preference (email, whatsapp, or ambos).1697. Trial expiration is irreversible: set status = blocked, do not auto-unblock without payment.1708. Metrics queries (MRR, faturamento) should use aggregateBillingMetrics(), not ad-hoc SQL.1719. New integrations must use `https://api.abacatepay.com/v2`, `/checkouts/create`, `/subscriptions/create`, and `/transparents/create` as appropriate. Keep `/v1/billing/*` and `billing.*` only inside an explicit legacy adapter.172173## Local Reference (example-saas)174175This skill is extracted from the example-saas SaaS billing system. The production codebase is at:176177- `{{USER_HOME}}/Documents/Code/example-saas/server/controllers/cobrancas.ts` — billing CRUD + processing + dunning178- `{{USER_HOME}}/Documents/Code/example-saas/server/controllers/abacatepay-webhook.ts` — webhook handler179- `{{USER_HOME}}/Documents/Code/example-saas/server/controllers/fatura.ts` — invoice lookup by shortlink180- `{{USER_HOME}}/Documents/Code/example-saas/server/controllers/trial.ts` — trial expiration processing181- `{{USER_HOME}}/Documents/Code/example-saas/server/services/abacatepay-create-billing-v2.ts` — AbacatePay billing creation182- `{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-sender.ts` — notification dispatch (email + WhatsApp)183- `{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-email-template.ts` — HTML invoice email template184- `{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-integrations-config.ts` — encrypted config management185- `{{USER_HOME}}/Documents/Code/example-saas/server/services/billing-metrics.ts` — MRR and billing metrics186- `{{USER_HOME}}/Documents/Code/example-saas/server/utils/invoice-state-machine.ts` — state machine logic187- `{{USER_HOME}}/Documents/Code/example-saas/server/cron/billing-cron.ts` — main billing scheduler188- `{{USER_HOME}}/Documents/Code/example-saas/server/cron/trial-cron.ts` — trial scheduler189- `{{USER_HOME}}/Documents/Code/example-saas/src/pages/FaturaPage.tsx` — public invoice page190- `{{USER_HOME}}/Documents/Code/example-saas/src/components/PlansPage.tsx` — pricing/plans page191- `{{USER_HOME}}/Documents/Code/example-saas/src/components/PlanManager.tsx` — user plan manager192- `{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminCobrancas.tsx` — admin billing CRUD193- `{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminPlanos.tsx` — admin plan CRUD194- `{{USER_HOME}}/Documents/Code/example-saas/src/components/AdminGlobalSettings.tsx` — global settings195- `{{USER_HOME}}/Documents/Code/example-saas/src/components/MinhasCobrancasSection.tsx` — user invoice list196- `{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20260617_cobrancas_foundation.sql` — core tables197- `{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20260617_cobrancas_website_final.sql` — shortlink trigger198- `{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20240101_billing_config.sql` — billing_config table199- `{{USER_HOME}}/Documents/Code/example-saas/supabase/migrations/20240117_partner_billing.sql` — partner billing200201## Reference Files202203- `billing-tables.md` — complete table schemas, indexes, enums, RLS policies204- `billing-flows.md` — detailed flow diagrams and pseudocode for each core flow205- `billing-config.md` — encryption, config resolution, and setup steps206- `billing-admin.md` — admin interfaces and CRUD operations207- `billing-notifications.md` — email/WhatsApp templates, dunning sequence, template variables208209## Validation210211- After changes, run build and typecheck (npm run build, npm run typecheck or equivalent)212- Simulate webhook: POST `checkout.completed` and `subscription.renewed` events and verify idempotent processing213- Test dunning: create overdue cobranca with regua de 0/3/7 dias and confirm notification dispatch214- Test trial: set trial_duration_days=1, create user, wait for pre-expiration and expiration215- Verify no AbacatePay/Resend/Evolution keys leak to browser bundles216- Run project lint when available217218## Related Skills219220- `skill-abacatepay-integration` — AbacatePay v2 API specifics and legacy v1 migration boundary221- `skill-saas-core-limits` — plan limits, entitlements, feature flags after payment222- `skill-evolution-api` — WhatsApp notification channel223- `skill-supabase-rls` — RLS policies for billing tables224- `skill-saas-factory` — top-level SaaS construction entry