Cómo montar suscripciones y cobro recurrente con la API Pagnovo

Productos, ofertas, suscripciones y facturas en la práctica — trial, ciclos, pausa y cancelación, estados de factura y los eventos que avisan antes del churn.

Equipo Pagnovo · 2026-08-07

El cobro recurrente parece simple hasta que hay que lidiar con trial, upgrade a mitad de ciclo, tarjeta vencida y cliente que pide pausa. Esta guía muestra cómo el modelo de la API Pagnovo organiza eso — y cómo usar sus eventos para reducir el churn.

Referencia completa: portal.pagnovo.com/docs.

El modelo: producto → oferta → suscripción → factura

La separación en cuatro capas parece burocracia al principio, pero es lo que evita retrabajo después:

Capa Qué representa Ejemplo
Producto Lo que vendes "Plan Profesional"
Oferta Cómo lo vendes R$ 299/mes, 7 días de trial
Suscripción Quién contrató qué Cliente X contrató la oferta Y
Factura Cada cobro generado Cobro de marzo

La ventaja: un mismo producto puede tener varias ofertas (mensual, anual, promocional, socio) sin duplicar registros. Y cambiar el precio de una oferta nueva no afecta a quien ya contrató la antigua.

Paso 1 — Cliente

POST /v2/customers

{
  "name": "Maria Silva",
  "email": "maria@empresa.com.br",
  "document": "12345678909"
}

⚠️ El document (CPF/CNPJ) es único e inmutable. No se puede corregir después. Valídalo antes de enviarlo — incluido el dígito verificador — porque un registro equivocado se convierte en un cliente duplicado que arrastras para siempre.

También existe GET /v2/customers/:id/history, útil para atención: muestra el historial del cliente sin que tengas que armarlo por tu lado.

Paso 2 — Producto y oferta

POST /v2/products
{ "name": "Plan Profesional" }
POST /v2/offers

{
  "productId": "...",
  "amount": 29900,
  "billingCycle": "MONTHLY",
  "billingCycleCount": 12,
  "trialDays": 7,
  "maxCycles": 24
}

Los campos que definen la economía del plan:

Los cupones e intereses usan basis points, no porcentaje directo: 1000 = 10%. Las multas fijas siguen en centavos. Confundirlo genera un descuento 100× mayor al pretendido.

Paso 3 — Suscripción

POST /v2/subscriptions

{
  "customerId": "...",
  "offerId": "...",
  "amount": 29900,
  "billingCycle": "MONTHLY"
}

Y el ciclo de vida completo, sin que tengas que implementarlo:

POST /v2/subscriptions/:id/pause     → pausa temporal
POST /v2/subscriptions/:id/resume    → reanuda
POST /v2/subscriptions/:id/cancel    → cancela
PATCH /v2/subscriptions/:id          → modifica (upgrade/downgrade)

Por qué "pausar" importa más de lo que parece

Cuando el cliente quiere irse, muchas veces no quiere irse para siempre — quiere parar dos meses. Si la única opción que ofreces es cancelar, conviertes una pausa en churn definitivo.

Ofrecer pausa en la pantalla de cancelación es una de las intervenciones de mayor retorno en productos de suscripción, y aquí es una sola llamada de API.

Paso 4 — Facturas y sus estados

Cada ciclo genera una factura, que recorre estos estados:

DRAFT → PENDING → PAID
                ↘ OVERDUE → (recuperación)
                ↘ CANCELED / EXPIRED / REFUNDED
Estado Significado
DRAFT Creada, aún no emitida
PENDING Emitida, esperando pago
PAID Pagada
OVERDUE Vencida — entra en la secuencia de cobranza
REFUNDED Reembolsada
CANCELED Cancelada antes del vencimiento
EXPIRED Expiró sin pago

Operaciones útiles: POST /v2/invoices/:id/cancel, POST /v2/invoices/:id/mark-refunded y POST /v2/invoices/:id/notifications/resend — este último reenvía la notificación al cliente, el primer paso de cualquier recuperación.

Paso 5 — Los eventos que evitan el churn

Aquí la integración deja de ser pasiva. Suscríbete a estos webhooks:

Evento Qué hacer
subscription.created Registrar; aún no es ingreso confirmado
subscription.activated Liberar acceso, iniciar onboarding
subscription.past_due 🚨 Actuar ahora — secuencia de cobranza
subscription.paused Suspender acceso, agendar contacto de retorno
subscription.canceled Cerrar acceso, lanzar encuesta de salida
subscription.expired Cerrar ciclo, ofrecer renovación

El evento más valioso es subscription.past_due. Avisa que el cobro falló — y la mayor parte de esos fallos son involuntarios (tarjeta vencida, límite insuficiente), es decir, clientes que quieren continuar.

Tratar el past_due con tono de aviso técnico, y no de cobranza, recupera mucho más:

✅ "¡Hola, Maria! El cobro de tu plan no pasó — normalmente es tarjeta vencida. Puedes actualizarla en 30 segundos aquí: [link]"

Combínalo con la secuencia de cobranza y reintentos espaciados.

Errores comunes

Checklist


Conoce la plataforma de Cobros Recurrentes y la documentación de la API. Habla con el equipo para diseñar tu modelo de suscripción.