Pagó con Stripe y no tiene acceso: qué falla en tu app con IA
Por qué un cliente paga con Stripe y tu app de Lovable o Bolt no le da acceso: webhooks, claves de prueba y live, correos que no coinciden y suscripciones.
Read in English →
Cuando un cliente paga y tu app lo sigue tratando como usuario gratis, casi siempre Stripe tiene el dinero y tu app nunca se enteró. Las causas de siempre son un webhook que no llega o que falla, claves de prueba y de producción mezcladas, o un pago que no se puede asociar al usuario correcto. Para saber cuál es, revisa el pago en Stripe, después el registro de entregas del webhook y luego los logs de tu función, en ese orden.
Esta guía recorre esas revisiones para apps hechas con Lovable, Bolt, v0, Replit o Cursor, que en su mayoría usan Stripe Checkout con Edge Functions de Supabase detrás.
¿Cómo se entera tu app de que alguien pagó?
Una app puede enterarse de un pago de tres maneras, y las apps hechas con IA usan las tres.
- La página de éxito. Después de pagar, Stripe devuelve al cliente a una página de tu app y la app da acceso ahí. Es la opción más débil: si el cliente cierra la pestaña, se queda sin conexión o la redirección falla, tu app nunca se entera.
- Webhooks. Un webhook es un mensaje que Stripe envía a una dirección de tu servidor cuando pasa algo, como un checkout completado o una suscripción renovada. Es lo que Stripe recomienda para dar acceso, porque llega aunque el cliente nunca vuelva a tu sitio.
- Consultar a Stripe directamente. Algunas integraciones le preguntan a Stripe el estado del cliente cada vez que inicia sesión. La integración de Stripe de Lovable funciona así por defecto y asocia al usuario con el cliente de Stripe por su correo.
Saber cuál usa tu app te dice dónde buscar. Si no lo sabes, pídele a la IA que te explique cómo da acceso la app después de un pago, sin cambiar nada.
Paso 1: Busca el pago en Stripe
Abre el Dashboard de Stripe y busca el pago por el correo del cliente.
- Mira el modo. Stripe guarda los datos de prueba (en sandboxes o en modo de prueba) totalmente separados de los reales. Si un cliente real pagó con dinero real, el pago está en modo live. Si tu app sigue usando claves de prueba, nunca lo va a ver.
- Mira el estado. "Succeeded" significa que Stripe tiene el dinero. Cualquier otro estado (incompleto, fallido, requiere acción) indica que el problema está en el propio checkout.
- Mira el correo. Anota el correo exacto del cliente en Stripe. Lo vas a necesitar en el paso 4.
Paso 2: Lee el registro de entregas del webhook
Si tu app usa webhooks, abre Workbench → Webhooks en Stripe y elige tu endpoint. La pestaña Event deliveries muestra cada evento que Stripe intentó enviar y qué respondió tu servidor.
Primero confirma que existe un endpoint en modo live. Un error común es crear el webhook durante las pruebas y nunca crear el de producción.
Luego mira los códigos de estado:
| Lo que ves | Lo que suele significar |
|---|---|
| 401 o 403 | Tu función rechazó la petición antes de leerla. Las Edge Functions de Supabase esperan por defecto el token de un usuario con sesión, así que la función del webhook necesita ese control desactivado y debe apoyarse en la firma de Stripe. |
| 400 | Falló la verificación de la firma. Casi siempre es el secreto de firma equivocado (whsec_…), el secreto de prueba usado en live, o código que procesó el cuerpo antes de verificarlo. Stripe necesita el cuerpo crudo, sin tocar. |
| 404 | La URL está mal, muchas veces porque la función cambió de nombre o se desplegó con otro. |
| 3xx | Tu servidor redirigió la petición (por ejemplo, del dominio raíz a www). Stripe cuenta las redirecciones como fallos. Usa la URL final. |
| 500 o tiempo agotado | El código se ejecutó y falló, o tardó demasiado. Lee los logs de la función. |
Stripe firma cada webhook con un secreto único para cada endpoint, y el de modo de prueba es distinto del de producción. Si lo copiaste mientras probabas, no va a servir en live.
Paso 3: Lee los logs de tu función
En Supabase, abre Edge Functions, elige la función que maneja Stripe (suele llamarse algo como stripe-webhook) y abre sus logs. Filtra por la hora del pago. Busca:
- Errores de firma o de un secreto que falta.
- Errores al escribir en la base de datos, como
new row violates row-level security policy. Puede que la función del webhook intente actualizar una tabla que no tiene permiso para tocar. - Un usuario que no se encontró.
Si usas Lovable Cloud, los logs están en la vista Cloud de Lovable. En Bolt, Vercel o Replit, busca en los logs de funciones o de despliegue de esa plataforma.
Paso 4: Comprueba que el pago coincide con el usuario correcto
Un webhook puede llegar perfecto y aun así no desbloquear nada, porque la app no sabe qué usuario pagó.
- Correos distintos. Si tu app asocia por correo, un cliente que inicia sesión con
ana@empresa.comy paga conana.personal@gmail.comno va a coincidir. Es una de las causas más comunes, y no se ve hasta que comparas las dos direcciones. - Ningún vínculo entre el usuario y el checkout. Una configuración más firme envía el ID del usuario con sesión al crear la Checkout Session (Stripe tiene el campo
client_reference_idpara eso, ymetadatapara lo demás) y guarda el ID de cliente de Stripe en el registro del usuario. Así el webhook sabe exactamente quién pagó.
Abre la fila del usuario en tu base de datos y revisa si tiene un ID de cliente de Stripe y un estado de suscripción. Si esos campos están vacíos, el webhook nunca los escribió.
¿Por qué las claves de prueba y producción dan tantos problemas?
Pasar de prueba a producción implica cambiar varias cosas a la vez, y si se te escapa una, los pagos fallan.
- Claves de API. La clave secreta (
sk_live_…en lugar desk_test_…) en los secretos de tu servidor, y la clave publicable en el frontend si tu app la usa. - Productos y precios. Los precios creados en modo de prueba no existen en live y tienen otros IDs. Si tu código tiene escrito un ID de precio de prueba, el checkout real falla.
- Endpoint del webhook y secreto de firma. Un endpoint live aparte, con su propio secreto
whsec_guardado en el servidor. - Volver a desplegar. Algunas plataformas solo leen los secretos nuevos después de un nuevo despliegue.
Una advertencia más, de la documentación de Lovable: su vista previa no tiene un entorno de prueba separado, así que si conectas una clave live, los pagos hechos desde la vista previa son reales.
¿Qué necesitan las suscripciones además del primer pago?
Una compra única necesita un evento. Una suscripción necesita que tu app siga sus cambios mientras dure. Los eventos que la mayoría de las apps tiene que manejar son:
checkout.session.completed: el cliente terminó el checkout. Crea o vincula la suscripción.invoice.paid: un pago se cobró, incluida cada renovación. Mantén el acceso.invoice.payment_failed: falló una renovación. Avisa al cliente antes de cortar el acceso.customer.subscription.updated: cambios de plan o una cancelación programada para el final del periodo.customer.subscription.deleted: la suscripción terminó. Quita el acceso.
Dos detalles hacen tropezar a muchas apps. Stripe no garantiza el orden de los eventos, así que tu código no debe suponer que checkout.session.completed llega antes que invoice.paid. Y el mismo evento puede llegar dos veces: guarda el ID de cada evento que procesas y salta los repetidos.
¿Cómo lo arreglas para los clientes que ya pagaron?
Una vez corregida la causa, todavía tienes clientes esperando.
- Deja que Stripe reintente. En modo live, Stripe sigue reintentando las entregas fallidas hasta por tres días. Si arreglas el endpoint a tiempo, muchos eventos llegarán solos.
- Reenvía eventos. Desde el Dashboard puedes reenviar un evento concreto hasta 15 días después de creado.
- Da acceso a mano a los que sean más antiguos, después de confirmar el pago en Stripe.
Después escríbeles. Un mensaje corto y honesto retiene a la mayoría.
¿Qué no debes hacer nunca mientras lo arreglas?
- Nunca pegues una clave secreta de Stripe en el chat de la IA, en un archivo de código ni en un mensaje. Guárdala solo en el almacén de secretos que te da tu plataforma.
- Nunca desactives la verificación de la firma para que desaparezcan los errores 400. Eso deja que cualquiera le mande a tu app un falso "pago completado".
- Si una clave secreta quedó expuesta alguna vez, rótala en el Dashboard de Stripe y actualiza tu servidor.
Nuestra checklist de seguridad para apps hechas con IA explica las claves con más detalle.
Respuestas rápidas
El cliente pagó y vio la página de éxito. ¿Por qué no tiene acceso? Puede que esa página no sea lo que da acceso. Revisa las entregas del webhook y la fila del usuario en la base de datos.
¿Puedo probar webhooks sin dinero real? Sí. Usa un sandbox o el modo de prueba con las tarjetas de prueba de Stripe; la Stripe CLI también puede enviar eventos de prueba a tu endpoint.
¿Le pido a la IA que lo arregle? Dale primero la evidencia: el código de estado de Event deliveries, el error del log y en qué modo estás. Pídele que te explique la causa antes de cambiar nada.
¿Siguen sin entrar los clientes que pagan?
Un error en los pagos te cuesta dinero cada día que sigue abierto. Pasa el chequeo gratis, mira cómo funciona nuestro rescate de apps hechas con IA o revisa nuestras páginas para apps de Lovable y Bolt. Si quieres una revisión completa, la Auditoría de rescate cuesta $299 e incluye un informe escrito en 2 días hábiles. Cuéntanos qué pasa y una persona te responde en un día hábil como máximo.


