Como montar assinaturas e cobrança recorrente com a API Pagnovo
Produtos, ofertas, assinaturas e faturas na prática — trial, ciclos, pausa e cancelamento, estados de fatura e os eventos que avisam antes do churn.
Equipe Pagnovo · 2026-08-07
Cobrança recorrente parece simples até você precisar lidar com trial, upgrade no meio do ciclo, cartão que expirou e cliente que pediu pausa. Este guia mostra como o modelo da API Pagnovo organiza isso — e como usar os eventos para reduzir churn.
Referência completa: portal.pagnovo.com/docs.
O modelo: produto → oferta → assinatura → fatura
A separação em quatro camadas parece burocracia no começo, mas é ela que evita retrabalho depois:
| Camada | O que representa | Exemplo |
|---|---|---|
| Produto | O que você vende | "Plano Profissional" |
| Oferta | Como você vende | R$ 299/mês, 7 dias de trial |
| Assinatura | Quem assinou o quê | Cliente X assinou a oferta Y |
| Fatura | Cada cobrança gerada | Cobrança de março |
A vantagem: um mesmo produto pode ter várias ofertas (mensal, anual, promocional, parceiro) sem duplicar cadastro. E mudar o preço de uma oferta nova não afeta quem já assinou a antiga.
Passo 1 — Cliente
POST /v2/customers
{
"name": "Maria Silva",
"email": "maria@empresa.com.br",
"document": "12345678909"
}
⚠️ O document (CPF/CNPJ) é único e imutável. Não dá para corrigir depois. Valide antes de
enviar — inclusive o dígito verificador — porque um cadastro errado vira um cliente duplicado que
você carrega para sempre.
Há também GET /v2/customers/:id/history, útil para atendimento: mostra o histórico do cliente sem
precisar montar isso do seu lado.
Passo 2 — Produto e oferta
POST /v2/products
{ "name": "Plano Profissional" }
POST /v2/offers
{
"productId": "...",
"amount": 29900,
"billingCycle": "MONTHLY",
"billingCycleCount": 12,
"trialDays": 7,
"maxCycles": 24
}
Os campos que definem a economia do plano:
amount— em centavos (R$ 299,00 =29900)billingCycle—MONTHLYouYEARLYtrialDays— período gratuito antes da primeira cobrançamaxCycles— encerra a assinatura após N ciclos (útil para planos com prazo definido)
Cupons e juros usam basis points, não porcentagem direta:
1000= 10%. Multas fixas continuam em centavos. Confundir isso gera desconto 100× maior que o pretendido.
Passo 3 — Assinatura
POST /v2/subscriptions
{
"customerId": "...",
"offerId": "...",
"amount": 29900,
"billingCycle": "MONTHLY"
}
E o ciclo de vida completo, sem você precisar implementar:
POST /v2/subscriptions/:id/pause → pausa temporária
POST /v2/subscriptions/:id/resume → retoma
POST /v2/subscriptions/:id/cancel → cancela
PATCH /v2/subscriptions/:id → altera (upgrade/downgrade)
Por que "pausar" importa mais do que parece
Quando o cliente quer sair, muitas vezes ele não quer sair para sempre — quer parar por dois meses. Se a única opção que você oferece é cancelar, você transforma uma pausa em churn definitivo.
Oferecer pausa na tela de cancelamento é uma das intervenções de maior retorno em produtos de assinatura, e aqui é uma chamada de API.
Passo 4 — Faturas e seus estados
Cada ciclo gera uma fatura, que percorre estes estados:
DRAFT → PENDING → PAID
↘ OVERDUE → (recuperação)
↘ CANCELED / EXPIRED / REFUNDED
| Estado | Significado |
|---|---|
DRAFT |
Criada, ainda não emitida |
PENDING |
Emitida, aguardando pagamento |
PAID |
Paga |
OVERDUE |
Vencida — entra na régua de cobrança |
REFUNDED |
Estornada |
CANCELED |
Cancelada antes do vencimento |
EXPIRED |
Expirou sem pagamento |
Operações úteis: POST /v2/invoices/:id/cancel, POST /v2/invoices/:id/mark-refunded e
POST /v2/invoices/:id/notifications/resend — esse último reenvia a notificação ao cliente, o
primeiro passo de qualquer recuperação.
Passo 5 — Os eventos que evitam churn
É aqui que a integração deixa de ser passiva. Assine estes webhooks:
| Evento | O que fazer |
|---|---|
subscription.created |
Registrar; ainda não é receita confirmada |
subscription.activated |
Liberar acesso, iniciar onboarding |
subscription.past_due |
🚨 Agir agora — régua de cobrança |
subscription.paused |
Suspender acesso, agendar contato de retorno |
subscription.canceled |
Encerrar acesso, disparar pesquisa de saída |
subscription.expired |
Encerrar ciclo, oferecer renovação |
O evento mais valioso é o subscription.past_due. Ele avisa que a cobrança falhou — e a maior
parte dessas falhas é involuntária (cartão expirado, limite insuficiente), ou seja, cliente que
quer continuar.
Tratar past_due com tom de aviso técnico, e não de cobrança, recupera muito mais:
✅ "Oi, Maria! A cobrança do seu plano não passou — normalmente é cartão vencido. Dá para atualizar em 30 segundos aqui: [link]"
Combine com a régua de cobrança e retentativas espaçadas.
Erros comuns
- Valor em reais.
299vira R$ 2,99. Sempre centavos. - Confundir basis points.
10não é 10% — é 0,1%. - Tratar
createdcomo receita. Sóactivatedsignifica acesso liberado. - Não oferecer pausa. Converte pausa temporária em cancelamento permanente.
- Ignorar
past_due. É o alerta mais acionável do conjunto. documenterrado no cadastro. Imutável — vira cliente duplicado.- Cancelamento só por telefone. Além de irritar, gera chargeback: o cliente vai ao banco quando não consegue cancelar com você.
Checklist
-
documentvalidado antes de criar o cliente - Valores em centavos; cupons em basis points
- Ofertas separadas por modalidade (não editar a oferta ativa)
- Acesso liberado em
subscription.activated, não emcreated -
past_dueconectado à régua de cobrança - Pausa oferecida antes do cancelamento
- Cancelamento autosserviço disponível
- Estados de fatura refletidos no seu sistema
Conheça a plataforma de Cobranças Recorrentes e a documentação da API. Fale com o time para desenhar seu modelo de assinatura.