Holograma de cobros fallidos en suscripciones: tarjeta de cristal naranja rodeada de flechas de reintento y alertas rojas
Software / APIs

Cobros Fallidos en Suscripciones: Reintentos y Dunning

Codezone
Codezone Empresa de Desarrollo Web y Software a Medida

Los cobros fallidos en suscripciones se recuperan con un proceso de dunning: reintentos programados según el motivo del rechazo y avisos que llevan al cliente a actualizar su método de pago antes de suspender el servicio. Parte de esa lógica la pone la pasarela y el resto vive en tu backend, que construimos dentro de las plataformas de suscripción a medida que desarrollamos en Madrid.

Una tarjeta caducada o un saldo insuficiente el día del cargo no significan que el cliente quiera irse. Si tu sistema cancela al primer fallo, pierdes una cuota que habría pagado. Si reintenta sin criterio una tarjeta robada, no recuperas nada. Igual que con las devoluciones de domiciliaciones SEPA en tu software, cada motivo de rechazo pide una respuesta distinta.

Al terminar sabrás qué fallos merece la pena reintentar y en qué momento cortar el acceso, dos decisiones que pesan en el coste real de una plataforma de suscripción.

Qué es el dunning de cobros fallidos en suscripciones

El dunning es el proceso que sigue una plataforma de suscripción cuando falla el cobro de una cuota. Combina reintentos del pago en fechas calculadas con avisos al cliente, y mantiene la cuenta en un estado intermedio hasta que paga o se da de baja. Su objetivo es evitar la baja involuntaria de quien quería seguir pagando.

Qué cobros fallidos merece la pena reintentar

Un cobro fallido merece reintento cuando el rechazo es temporal, y no lo merece cuando el banco emisor lo rechaza de forma definitiva:

  • Rechazo blando: fondos insuficientes o un fallo puntual del emisor. Se reintenta otro día.
  • Rechazo duro: tarjeta robada, perdida o con número incorrecto. Stripe no lo reintenta hasta que el cliente aporta un método de pago nuevo.
  • Autenticación requerida: el banco pide que el cliente confirme el cargo. Le envías un enlace para que lo autentique.

La documentación de Smart Retries de Stripe recomienda por defecto 8 intentos en 2 semanas. Para adeudos SEPA, si activas los reintentos de métodos de pago locales, Stripe hace como máximo 2 reintentos en 30 días y solo por fondos insuficientes.

Si cobras con remesas propias, el código de motivo de cada devolución sustituye al código de rechazo de la tarjeta, y la conciliación bancaria automática con el extracto te lo entrega casado con su factura.

Anillo holográfico naranja con pulsos de luz espaciados que orbitan un núcleo de cristal en una sala oscura y reflectante
Cada reintento cae en una fecha elegida, no al azar.

Estados de la suscripción y acceso al servicio

El estado de la suscripción decide qué ve el cliente mientras dura el dunning. Stripe Billing usa, entre otros, estos estados, y conviene reflejarlos en tu propio modelo:

  • active: al corriente de pago. Acceso completo.
  • past_due: la última factura falló y siguen los reintentos. Periodo de gracia con acceso y aviso visible.
  • unpaid: reintentos agotados. La suscripción sigue viva, pero no se cobra. En ese punto revoca el acceso.
  • canceled: estado final. Para volver, el cliente necesita una suscripción nueva.

Qué ocurre al agotar los reintentos lo eliges en la configuración: cancelar, marcar como unpaid, dejar en past_due o pausar. En un marketplace con pagos divididos y Stripe Connect, ese estado decide además qué liquidas a cada vendedor.

Cuatro plataformas holográficas escalonadas en naranja y ámbar unidas por haces de luz, la última apagada en rojo
La cuenta pasa por estados intermedios antes de llegar a la baja.

Avisos y actualización del método de pago

Cada aviso de dunning busca que el cliente actualice su método de pago con un solo enlace. Una secuencia razonable:

  • Primer fallo: aviso informativo con enlace seguro para cambiar la tarjeta, sin tono de reclamación.
  • Antes del último reintento: aviso con la fecha en que se suspenderá el acceso.
  • Suspensión: aviso con la forma de reactivar la cuenta.
  • Reactivación: confirmación del pago y del acceso restaurado.

Estos avisos comparten plantillas y envíos con el resto de comunicaciones si usas el motor de automatización de marketing del CRM. Parte de los fallos se evita antes: Stripe intenta actualizar con las redes de tarjetas las que el emisor ha sustituido, con una cobertura que varía por país, y lo notifica con el evento payment_method.automatically_updated. Para saldar la deuda sin tarjeta, un pago puntual con Bizum para reactivar la cuenta es otra vía.

Bajas: cuándo cancelar y cómo dejar salir al cliente

La baja voluntaria debe ser tan sencilla como el alta. El artículo 62.3 del texto refundido de la ley de consumidores permite al consumidor poner fin al contrato en la misma forma en que lo celebró, sin cargas desproporcionadas.

Separa en tus datos la baja voluntaria de la baja por impago, porque se corrigen con acciones distintas. Un almacén de datos con el histórico de cobros cruza ambas bajas y te dice cuánto recupera cada reintento.

Flujo de esferas naranjas que entra en un embudo holográfico violeta y sale ordenado en una sola fila de luz
Cada evento del proveedor se procesa una sola vez y en orden.
CodeZone Pro Tip: traduce los webhooks de Stripe a un estado interno de la cuenta y a acciones de aviso, ignorando eventos duplicados.
// Rechazos que Stripe no reintenta sin un método de pago nuevo (documentación de Smart Retries)
const RECHAZOS_DUROS = new Set(["incorrect_number", "lost_card", "pickup_card", "stolen_card",
  "revocation_of_authorization", "revocation_of_all_authorizations", "authentication_required",
  "highest_risk_level", "transaction_not_allowed"]);
// El acceso lo decide tu estado interno, no el del proveedor: así puedes cambiar de pasarela
const ESTADOS = { active: "activa", past_due: "en_gracia", unpaid: "suspendida", canceled: "baja" };
const procesados = new Set(); // en producción, tabla con índice único por event.id

function aplicarEvento(evento, cuenta) {
  if (procesados.has(evento.id)) return []; // Stripe puede entregar un evento más de una vez
  procesados.add(evento.id);
  const obj = evento.data.object;
  switch (evento.type) {
    case "payment_intent.payment_failed": {
      const motivo = obj.last_payment_error?.decline_code;
      if (motivo === "authentication_required") return ["enviar_enlace_autenticacion"];
      return RECHAZOS_DUROS.has(motivo) ? ["pedir_nuevo_metodo_de_pago"] : [];
    }
    case "invoice.payment_failed":
      cuenta.intentos = obj.attempt_count;
      // Sin próximo intento, aviso final (con automations de Stripe, next_payment_attempt llega en invoice.updated)
      return obj.next_payment_attempt ? ["aviso_reintento"] : ["aviso_final"];
    case "customer.subscription.updated":
      cuenta.estado = ESTADOS[obj.status] ?? cuenta.estado;
      return cuenta.estado === "suspendida" ? ["revocar_acceso"] : [];
    case "invoice.paid":
      Object.assign(cuenta, { estado: "activa", intentos: 0 });
      return ["restaurar_acceso"];
    default:
      return [];
  }
}

console.log(aplicarEvento({ id: "evt_1", type: "invoice.paid", data: { object: {} } }, { estado: "en_gracia" }));
module.exports = { aplicarEvento };

Con esta capa, el acceso del cliente depende de un estado que controlas tú y cada aviso sale una sola vez. Si el volumen crece, encolar cada evento al recibirlo evita perder alguno, como explicamos al ver cuándo usar webhook o cola de mensajes.

El Coste de Dar de Baja a Quien Quería Seguir Pagando

Cancelar al primer fallo convierte un problema de tarjeta en una baja. Un dunning medido recupera esas cuotas y deja la cancelación para quien de verdad no va a pagar.

Puerta holográfica naranja entreabierta con partículas que regresan al interior bajo una luz violeta
Una cuota recuperada mantiene dentro a quien quería quedarse.

En Codezone desarrollamos la lógica de cobro y dunning de plataformas de suscripción. Cuéntanos cómo gestionas hoy los impagos y te proponemos el flujo.