Webhooks de Stripe (Humano)

En el panel de Stripe (Developers → Webhooks), crea un destino que envíe eventos a esta aplicación. Humano usa Laravel Cashier y controladores propios para suscripciones, facturas y comisiones de afiliados.

URL del endpoint

Método: POST

Ruta en tu sitio /stripe/webhook

URL completa (sustituye el dominio por el público de tu entorno, alineado con APP_URL):

https://wapify.me/stripe/webhook

En staging y producción Stripe debe poder llamar a tu URL por HTTPS.

Añadir eventos en el Dashboard de Stripe

Si tu webhook solo tiene suscripciones e invoice.payment_succeeded, faltan eventos necesarios para transferencias externas y actualizaciones de estado. Sigue estos pasos en producción (modo Live):

  1. Abre Developers → Webhooks (o Event destinations en Workbench): https://dashboard.stripe.com/webhooks
  2. Confirma que el selector superior está en Live, no en Test.
  3. Abre el endpoint que apunta a tu app (POST /stripe/webhook).
  4. Pulsa Edit destination, Update details o Configure.
  5. En Events to send / Select events, pulsa Add events o + Select events.
  6. Busca la categoría Invoice y marca invoice.paid e invoice.updated (mantén los que ya tienes).
  7. Opcional: añade invoice.payment_failed.
  8. Guarda con Update endpoint / Save.

Lista mínima recomendada (Listening to)

Customer

  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted

Invoice

  • invoice.paid
  • invoice.payment_succeeded
  • invoice.updated
  • invoice.payment_failed (También recomendados)
Por qué invoice.paid es imprescindible

invoice.payment_succeeded no cubre todos los cobros. Humano usa invoice.paid para marcar la factura como cobrada cuando Stripe registra el pago por transferencia externa u otros métodos sin cargo ch_.

Tipo de cobro invoice.payment_succeeded invoice.paid
Tarjeta / cargo normal (ch_)
Transferencia externa marcada en Stripe A veces no

invoice.updated actúa como respaldo: cuando la factura pasa a paid, void o uncollectible, Humano refresca staging e importa al core.

Eventos a habilitar

Selecciona como mínimo los siguientes. Cubren la sincronización de Cashier, tu lógica de facturas y cambios de plan:

  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.paid
  • invoice.payment_succeeded
  • invoice.updated
  • invoice.payment_failed

También recomendados

  • customer.updated
  • payment_method.automatically_updated

Si la app crea sesiones de Stripe Checkout (suscripciones o registro con pago), añade también:

  • checkout.session.completed
Comprobar que funciona
  1. En la ficha del webhook, abre Event deliveries / Recent deliveries.
  2. Tras un cobro real, deberías ver invoice.paid con respuesta HTTP 200.
  3. Prueba manual: Send test webhook → elige invoice.paid → confirma 200 OK.
  4. Si ves 4xx o 5xx, revisa la URL del endpoint, STRIPE_WEBHOOK_SECRET y que el worker de colas esté activo (el job va en cola).
Respaldo automático si el webhook no llega

Humano ejecuta tareas programadas que sincronizan facturas y crean pagos faltantes. No sustituyen al webhook, pero corrigen desfases en minutos:

  • stripe:sync-invoices — cada 10 min (refresca invoice_syncs desde la API)
  • invoice-syncs:import-stripe --reconcile — cada 10 min (actualiza balance y estado en invoices)
  • invoices:reconcile-stripe-collected-payments — :20 y :50 (crea pagos faltantes)
Desarrollo local

Stripe no puede llegar a https://*.test desde internet. Usa Stripe CLI y el signing secret que muestra (por ejemplo en STRIPE_WEBHOOK_SECRET):

stripe listen --forward-to https://wapify.me/stripe/webhook
Opcional: cuentas Stripe por categoría

Si usas cuentas Stripe distintas por categoría, configura un endpoint por categoría. Valores permitidos: mentoring, mailer, prospecting, hosting, support. Ejemplo:

https://wapify.me/stripe/webhook/mailer
Alcance del destino y versión de API

Usa “Your account” salvo que operes como plataforma Stripe Connect y recibas eventos de cuentas conectadas. Elige una versión de API compatible con tu SDK; si el payload difiere, alinea la versión del dashboard con tu proyecto.

Signing secret

Tras crear el endpoint, copia el signing secret en STRIPE_WEBHOOK_SECRET (o en stripe_accounts.{categoría}.webhook_secret para URLs por categoría). La ruta está excluida de verificación CSRF.