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:

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

Checklist


Conheça a plataforma de Cobranças Recorrentes e a documentação da API. Fale com o time para desenhar seu modelo de assinatura.