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 pagamentopaid: paga,released_atsetado, conteúdo liberadooverdue: vencida, entra na régua de cobrançacancelled: cancelada manualmente ou por expiraçãorefunded: estornada (transição exclusiva depaid)
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.completedorsubscription.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 emailevolution_config: Evolution API URL + API key + instanceabacatepay_config: AbacatePay API keytrial_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, andsubscription.cancelled. The legacy v1billing.*events belong behind a migration adapter. - Resend: keep the key server-side and send through the official SDK or
POST https://api.resend.com/emailswithAuthorization: Bearer <key>and aUser-Agent; useIdempotency-Keyfor retryable sends, record provider request IDs, and redact message content from logs. - Evolution API: use the deployed v2 documentation and
apikeyheader; 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/createas appropriate. Keep/v1/billing/*andbilling.*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 policiesbilling-flows.md— detailed flow diagrams and pseudocode for each core flowbilling-config.md— encryption, config resolution, and setup stepsbilling-admin.md— admin interfaces and CRUD operationsbilling-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.completedandsubscription.renewedevents 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 boundaryskill-saas-core-limits— plan limits, entitlements, feature flags after paymentskill-evolution-api— WhatsApp notification channelskill-supabase-rls— RLS policies for billing tablesskill-saas-factory— top-level SaaS construction entry


