Pagos fallidos y dunning: recupera los ingresos de suscripción que pierdes en silencio (Stripe, 2026) — Cesar Ayala
← Todos los artículos

Pagos fallidos y dunning: recupera los ingresos de suscripción que pierdes en silencio (Stripe, 2026)

El churn involuntario son ingresos de suscripción perdidos por cargos de tarjeta fallidos, no clientes que se van. Recupéralos con un stack: Stripe Smart Retries (tiempos por ML), correos de dunning automáticos más un Customer Portal self-serve, y Card Account Updater. Controla el acceso con invoice.payment_failed y la máquina de estados past_due a unpaid, nunca desde el cliente.

¿Qué es el churn involuntario y por qué es mayor de lo que crees?

Cuando un cliente cancela tu SaaS, al menos sabes por qué: el precio, un competidor, una funcionalidad que no llegó. Eso es churn voluntario, y duele. Pero hay otro tipo de churn que rara vez aparece en tus juntas de producto y que probablemente te está costando más: el churn involuntario.

El churn involuntario son suscripciones que pierdes porque el cargo a la tarjeta falló, no porque el cliente decidiera irse. Tarjetas expiradas, tarjetas reemitidas (el banco mandó plástico nuevo con otro número), límites excedidos, declines del emisor. El cliente quería seguir pagándote. Simplemente el cargo no pasó, y si no haces nada, esa suscripción se cae sola.

La diferencia importa porque cambia qué herramienta usas. El churn voluntario es un problema de producto y de pricing: lo resuelves con mejor onboarding, mejor valor, mejores planes. El churn involuntario es un problema de infraestructura de billing: lo resuelves con configuración y código en Stripe. Y a diferencia del voluntario, el involuntario es en gran parte recuperable. Esa misma tarjeta que falló hoy probablemente funciona la semana que viene, o el cliente solo necesita un correo que le recuerde actualizarla.

Mi opinión, después de operar esto con dinero real: la mayoría de los equipos no instrumentan bien este churn porque se esconde dentro de un solo número. Ves “5% de churn mensual” y asumes que es problema de retención de producto. Pero si separas las cancelaciones reales de los pagos fallidos, muchas veces descubres que una rebanada enorme de ese 5% son cargos que nunca recuperaste. Esa rebanada es la que recuperas con dunning, no con un rediseño del producto.

Churn voluntario vs. churn involuntario

Voluntario

  • El cliente decide cancelar
  • Causa: producto, precio, competidor
  • Se ataca con producto y pricing
  • Difícil de revertir una vez que se van

Involuntario

  • El cargo a la tarjeta falla
  • Causa: tarjeta expirada, reemitida o declinada
  • Se ataca con configuración y código en Stripe
  • En gran parte recuperable: el cliente quería pagar
El voluntario es producto/pricing y es difícil de revertir; el involuntario es billing y en gran parte se recupera.

Antes de seguir: todo esto asume que ya tienes suscripciones y webhooks funcionando. Si no, empieza por cómo integrar Stripe en tu SaaS, que es la base sobre la que se construye todo lo demás.

¿Cómo funcionan realmente los Stripe Smart Retries?

La primera capa de recuperación es reintentar el cargo. La pregunta es cuándo. Un calendario fijo (reintenta a las 24h, luego a las 72h, luego al día 7) funciona, pero es ciego: no sabe nada del cliente ni de su tarjeta.

Smart Retries es parte de Revenue Recovery de Stripe Billing y resuelve justo eso. En lugar de un calendario fijo, usa machine learning entrenado sobre la red de Stripe para elegir el mejor momento de reintento para cada pago fallido. Usa señales como la actividad reciente de la tarjeta y el mejor momento para cobrar según patrones de ese emisor. La idea es simple: si el modelo “sabe” que esa tarjeta tiende a tener fondos los viernes, reintenta el viernes en vez de mañana a las 3 de la mañana.

Tú no programas los reintentos uno por uno. Configuras una política de reintentos: cuántas veces reintentar dentro de una ventana. Las ventanas disponibles son de 1 semana, 2 semanas, 3 semanas, 1 mes o 2 meses. Stripe se encarga del timing exacto dentro de esa ventana; tú decides qué tan agresivo quieres ser y cuánto tiempo le das a un cobro fallido antes de rendirte.

Activar Smart Retries es cuestión de configuración en el dashboard de Billing, no de código. Conceptualmente, lo que defines es esto:

// Smart Retries se activa en Billing > Revenue Recovery (no por API).
// Lo que defines es la POLÍTICA, no cada reintento:
//
//   - Estrategia de reintentos: Smart Retries (timing por ML)
//   - Ventana de reintento: 1 semana | 2 semanas | 3 semanas | 1 mes | 2 meses
//   - Estado final tras el último intento: unpaid o canceled
//
// Stripe elige el momento óptimo de cada reintento DENTRO de esa ventana.
// Tu código solo reacciona a los webhooks que resultan de esos intentos.

Una nota práctica: la ventana es una decisión de negocio. Para B2C de ticket bajo, 2 semanas suele ser suficiente y evita molestar de más. Para B2B donde el contrato vale mucho, un mes o dos meses tiene sentido porque cada recuperación paga con creces el esfuerzo. No hay una respuesta universal; mídela. Detalles oficiales en Revenue Recovery.

El flujo de recuperación de un cargo fallido

Falla el cargoinvoice.payment_failed; la suscripción pasa a past_due
Smart RetriesML elige el momento de cada reintento dentro de tu ventana
Dunning + Customer Portalcorreo automático y ruta self-serve para actualizar la tarjeta
Recuperadoun reintento pasa o el cliente arregla la tarjeta: vuelve a active
unpaid o canceledsi se agota la ventana sin éxito, revocas acceso aquí
Smart Retries reintenta en la ventana que defines; en paralelo corren dunning y portal; al final ramifica a recuperado o a unpaid/canceled.

Correos de dunning y self-serve: ¿cómo logras que los clientes arreglen su propia tarjeta?

Reintentar la misma tarjeta solo te lleva hasta cierto punto. Si la tarjeta expiró de verdad o el banco la canceló, ningún reintento la va a revivir. Necesitas que el cliente capture una tarjeta nueva, y para eso sirve el dunning.

Stripe puede enviar correos automáticos cuando un pago falla, avisándole al cliente y pidiéndole que actualice su método de pago. Esto se configura en los ajustes de Billing, sin código. Pero el correo por sí solo no recupera nada: lo que recupera es la ruta de un solo clic detrás del correo.

Por eso emparejas el dunning con el Customer Portal de Stripe o con la hosted invoice page. El correo lleva al cliente a una página alojada por Stripe donde ingresa su tarjeta nueva sin tener que entrar a tu app, sin contactar a soporte, sin fricción. El cliente arregla su propio pago y la suscripción se recupera sola.

Mi opinión: el correo de dunning vale exactamente lo que vale el camino de actualización que tiene detrás. Si el correo dice “actualiza tu tarjeta” y el botón lleva a una pantalla de login de tu app que pide password que el cliente olvidó, perdiste. El Customer Portal de Stripe le quita ese tropiezo: link directo, página de Stripe, listo. Configura el portal y deja que Stripe mande los correos; es de las cosas con mejor relación esfuerzo/recuperación que vas a activar.

¿Puedes prevenir los fallos antes de que ocurran con Card Account Updater?

Todo lo anterior es recuperación: el cargo ya falló y estás corriendo a arreglarlo. La capa más barata es la que evita que el cargo falle en primer lugar.

Card Account Updater hace justo eso. Se comunica con las redes de tarjetas y los emisores para refrescar automáticamente los datos de las tarjetas guardadas (nueva fecha de expiración, número reemitido) antes de que un cargo falle. Si el banco le mandó a tu cliente una tarjeta nueva con otro número, Card Account Updater actualiza el método de pago guardado para que el siguiente cobro use los datos correctos. La falla nunca ocurre, así que nunca entra al flujo de reintentos ni de dunning.

La network tokenization ayuda en la misma dirección: en lugar de guardar el número de tarjeta crudo, se usa un token de red que el emisor puede mantener válido aunque el plástico cambie. Menos fricción, menos declines por datos viejos.

Mi opinión es directa: la recuperación más barata es la falla que nunca sucede. Card Account Updater no aparece en ninguna métrica de “pagos recuperados” porque su trabajo es que el pago nunca falle, pero es probablemente la palanca con mejor ROI de todo el stack. Actívala primero.

El stack de recuperación, en capas ordenadas

  1. 1. Card Account UpdaterPrevenir: refresca tarjetas expiradas o reemitidas antes de cobrar
  2. 2. Smart RetriesRe-temporizar: ML elige cuándo reintentar el cargo fallido
  3. 3. Correos de dunningAvisar: Stripe le pide al cliente que actualice su tarjeta
  4. 4. Customer Portal self-serveResolver: el cliente captura una tarjeta nueva en una página de Stripe
Empieza por prevenir; luego re-temporiza el cobro; luego avisa al cliente; luego dale una ruta para arreglarlo solo.

¿Cómo controlas el acceso con la máquina de estados past_due y los webhooks?

Aquí es donde el código importa y donde la gente más se equivoca. La regla de oro: el acceso a tu producto se decide desde los webhooks verificados de Stripe, nunca desde el cliente. El navegador del usuario te puede decir lo que sea; el evento de Stripe es la única fuente de verdad.

El flujo de estados es así. Cuando un cargo de suscripción falla, Stripe emite invoice.payment_failed y la suscripción pasa a past_due. Mientras Smart Retries hace su trabajo, la suscripción se queda en past_due y el campo next_payment_attempt te dice cuándo es el siguiente reintento. Si todos los reintentos de tu ventana se agotan sin éxito, la suscripción pasa a unpaid o canceled, según lo que hayas configurado.

El error clásico es revocar el acceso en la primera falla. No lo hagas. La primera falla solo significa “empezó el periodo de gracia”. Revocas acceso cuando la máquina de estados llega a unpaid o canceled, no antes. Si cortas en la primera falla, le quitas el producto a un cliente que probablemente iba a recuperarse en el segundo reintento, y eso es churn que tú mismo causaste.

Así se ve un handler mínimo. Verifica la firma del webhook (omitido aquí por brevedad), revisa next_payment_attempt (y registra attempt_count), y solo revoca cuando ya no hay más reintentos:

// POST /webhooks/stripe  — el evento es la fuente de verdad, no el cliente.
async function handleStripeEvent(event) {
  switch (event.type) {
    case 'invoice.payment_failed': {
      const invoice = event.data.object;

      // ¿Hay otro reintento programado? Entonces seguimos en periodo de gracia.
      if (invoice.next_payment_attempt) {
        // No revoques. Opcional: marca el estado como "en riesgo" en tu DB.
        await markAtRisk(invoice.customer, {
          attemptCount: invoice.attempt_count,
          nextAttempt: invoice.next_payment_attempt,
        });
        return;
      }

      // Sin próximo intento = se agotó la ventana de Smart Retries.
      // La suscripción pasará a unpaid o canceled según tu config.
      await revokeAccess(invoice.customer); // revocar aquí, no en la 1ra falla
      return;
    }

    case 'customer.subscription.updated': {
      const sub = event.data.object;
      // Reconcilia acceso contra el estado real de la suscripción.
      if (sub.status === 'active') await grantAccess(sub.customer);
      if (sub.status === 'unpaid' || sub.status === 'canceled') {
        await revokeAccess(sub.customer);
      }
      return;
    }
  }
}

Fíjate que no confío en un solo evento: uso invoice.payment_failed para decidir periodo de gracia y reconcilio el acceso contra el status real de la suscripción. Concede y revoca siempre contra estos eventos verificados.

¿Qué tasa de recuperación deberías esperar honestamente?

Aquí toca ser honesto, porque hay mucho número optimista circulando. Stripe cita que los negocios recuperan en promedio alrededor del 55% de los pagos fallidos. Es un número real y citable, pero es un promedio sobre toda su base; trátalo como referencia, no como tu pronóstico, y confírmalo para tu propio negocio.

Los datasets independientes muchas veces reportan números más bajos en el mundo real, sobre todo en B2C, del orden de 25% a 38%. Y un detalle importante: Smart Retries por sí solo tiende a quedar más abajo que el stack completo. Si solo prendes reintentos y nada más, vas a recuperar menos de lo que esperas.

Lo que de verdad mueve la aguja es combinar las palancas: Card Account Updater para prevenir, más Smart Retries para re-temporizar, más correos de dunning, más el Customer Portal self-serve. Cada capa atrapa fallas que las otras dejan pasar. Ninguna palanca individual le gana al stack completo.

Sé honesto con tu tasa de recuperación

Stripe cita (promedio)~55% de pagos fallidos recuperados
Datos independientes B2C~25–38% en muchos casos
Smart Retries soloqueda por debajo del stack completo
Tu número realmídelo tú; no asumas el promedio
Usa el promedio citado como referencia, pero mide el número real de tu negocio.

Mídelo tú mismo. Separa el churn involuntario del voluntario en tus métricas y rastrea qué porcentaje de cargos fallidos terminan recuperados. Si necesitas montar ese tablero, mi guía de métricas de facturación SaaS (MRR, churn) te da las definiciones para medir exactamente el churn que estás recuperando.

Preguntas frecuentes: respuestas rápidas sobre pagos fallidos y dunning

¿Cuándo debo revocar el acceso? Cuando la suscripción llega a unpaid o canceled tras el último reintento, no en la primera falla. La primera falla es el inicio del periodo de gracia; revocar ahí causa churn que tú mismo provocas.

unpaid vs. canceled: ¿cuál elijo como estado final? unpaid mantiene la suscripción existiendo (puedes reactivarla si el cliente vuelve a pagar después), mientras que canceled la cierra. Si esperas que clientes regresen y quieres recuperarlos sin recrear todo, unpaid te da más flexibilidad. Elige según qué tan probable sea la recuperación tardía en tu negocio.

¿Smart Retries reemplaza los correos de dunning? No, se apilan. Smart Retries reintenta la misma tarjeta en el mejor momento; el dunning consigue que el cliente capture una tarjeta nueva cuando la vieja ya no sirve. Resuelven problemas distintos y los quieres ambos.

¿Los reintentos van a chocar con Radar o con detección de fraude? Los reintentos legítimos de suscripción son cobros recurrentes esperados; no son el patrón que dispara fraude. Aun así, si usas Radar / 3D Secure, prueba tu flujo y revisa que tu política de reintentos no genere fricción innecesaria. No inventes reintentos manuales encima de Smart Retries.

¿Debo confiar en que el cliente me diga que el pago pasó? No, nunca. El evento de webhook es la fuente de verdad. El frontend te puede decir “pago exitoso” por mil razones equivocadas; concede acceso solo cuando Stripe te lo confirma por webhook.

¿B2B y B2C esperan lo mismo? No. En B2B los contratos valen más, así que ventanas de reintento más largas (1–2 meses) y dunning más persistente se pagan solos. En B2C de ticket bajo, ventanas cortas y un portal self-serve impecable suelen rendir mejor.

El stack recomendado, en un párrafo

Si solo te llevas una cosa: prende las cuatro capas juntas. Card Account Updater para prevenir las fallas de tarjetas expiradas o reemitidas, Smart Retries para reintentar en el momento óptimo dentro de la ventana que elijas, correos de dunning automáticos, y el Customer Portal self-serve para que el cliente arregle su propia tarjeta sin tocar a soporte. Controla el acceso desde invoice.payment_failed y la máquina de estados past_due a unpaid/canceled, nunca desde el cliente, y revoca solo después del último reintento. Mide tu propia tasa de recuperación en vez de confiar en el promedio citado. Esta resiliencia de billing no es un lujo de etapa tardía; es de las cosas que vale la pena dejar bien desde el principio, como discuto en cuánto cuesta construir un MVP de SaaS. Empieza por los docs oficiales de Smart Retries y Revenue Recovery, y deja de perder en silencio ingresos que ya habías ganado.