Pagos con Stripe en Laravel 13: suscripciones con Cashier paso a paso
Montar pagos con Stripe por suscripción desde cero solía ser semanas de código: customers, precios, invoices, webhooks y estados. Con Laravel Cashier en Laravel 13 es un trabajo de horas: un trait, un checkout y un webhook. Así se lleva una app a cobrar en producción con Stripe.
Qué es Laravel Cashier y por qué usarlo con Stripe
Laravel Cashier es el paquete oficial de Laravel para facturación por suscripción. Añade una interfaz fluida sobre la API de Stripe y elimina el boilerplate que toda app de pagos repite: creación de customers, suscripciones, facturas, cupones y métodos de pago. La documentación oficial de Cashier para Laravel 13.x es la referencia de esta guía.
Qué resuelve: suscripciones, facturas y webhooks de serie
Con el paquete instalado, tu modelo de usuario gana métodos para suscribirse, cancelar, cambiar de plan, listar facturas o descargar PDFs sin escribir llamadas directas a Stripe. Además, Cashier escucha los eventos de Stripe más comunes y sincroniza el estado de las suscripciones en tu base de datos, incluida la cancelación automática por cargos fallidos.
Lo que NO debes hacer: guardar tarjetas en tu base de datos
El argumento de seguridad que muchos olvidan: con Stripe Checkout, los datos de tarjeta se procesan en los servidores de Stripe y nunca pasan por tu aplicación. Tu servidor solo maneja identificadores de clientes y de métodos de pago. Eso simplifica el cumplimiento de PCI DSS y elimina la responsabilidad de custodiar datos sensibles. Si te ves tentado a guardar números de tarjeta, esa es la señal de que el enfoque es incorrecto.
Instalación y configuración en Laravel 13
Laravel 13 se publicó el 17 de marzo de 2026 y requiere PHP 8.3 como mínimo. Para esta guía da igual si vienes de Laravel 12 o de versiones anteriores: Cashier se instala igual, y si acabas de actualizar, nuestro artículo de novedades de Laravel 13 te muestra qué cambió en el framework.
composer require laravel/cashier y migraciones
Instala el paquete y publica sus migraciones con dos comandos:
composer require laravel/cashier
php artisan vendor:publish --tag=cashier-migrations
php artisan migrateLas migraciones añaden a la tabla de usuarios las columnas stripe_id, pm_type y pm_last_four, además de las tablas de suscripciones. Todo el esquema lo gestiona Cashier; no hay que crear nada a mano.
Claves de Stripe en el .env y modo test
Copia las claves del panel de Stripe a tu .env. Durante el desarrollo usa siempre las de test, que empiezan por sk_test y pk_test:
STRIPE_KEY=pk_test_...
STRIPE_SECRET=sk_test_...Con las claves de test, todo el flujo funciona con tarjetas de prueba como 4242 4242 4242 4242 y ningún cargo real. Es el modo que debes usar mientras desarrollas y el que necesitarás para las pruebas locales del final de esta guía.
El trait Billable en el modelo User
Añade el trait Billable a tu modelo de usuario:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}A partir de ese momento, cada usuario es un customer de Stripe bajo demanda: Cashier lo crea automáticamente en el primer cobro, sin que tú tengas que llamar a la API de Stripe para gestionar clientes.
Primera suscripción con Stripe Checkout
Checkout es la página de pago alojada por Stripe: el usuario introduce la tarjeta en el dominio de Stripe y tu app nunca ve los datos. Es la vía recomendada por el propio Stripe y la más corta para empezar a cobrar.
Crear el producto y el precio en el panel de Stripe
En el panel de Stripe crea un producto (por ejemplo, Plan Pro) y un precio recurrente mensual. Anota el ID del precio, que tiene la forma price_...; es el valor que usarás en el código para referenciar el plan.
Redirigir al usuario con el método checkout()
En el controlador, genera una sesión de Checkout y redirige al usuario:
return $request->user()->checkout([
'price_pro' => 1,
], [
'success_url' => route('dashboard'),
'cancel_url' => route('pricing'),
]);El primer array asocia precios con cantidades; el segundo configura a dónde vuelve el usuario tras pagar o cancelar. Sustituye price_pro por el ID real de tu precio.
El webhook: saber cuándo empieza la suscripción
Algunos métodos de pago tardan unos segundos en procesarse, así que la vuelta desde Checkout no garantiza que la suscripción exista ya. Ahí entra el webhook: Stripe notifica a tu servidor los eventos y Cashier actualiza la base de datos. Registra la ruta estándar:
Route::post('/stripe/webhook', [StripeWebhookController::class, 'handleWebhook'])
->name('cashier.webhook');Cashier maneja automáticamente la cancelación de suscripciones por cargos fallidos y otros eventos comunes; para eventos adicionales, el paquete lanza eventos propios que puedes escuchar con listeners.
Gestionar el ciclo de vida de la suscripción
La suscripción no termina al cobrar el primer mes: hay que poder cancelarla, reanudarla y cambiar de plan sin tocar el panel de Stripe. Cashier expone métodos directos sobre la suscripción activa del usuario.
Cancelar, reanudar y cambiar de plan (swap)
$user->subscription('default')->cancel();
$user->subscription('default')->resume();
$user->subscription('default')->swap('price_enterprise');Cancelar mantiene el acceso hasta el final del periodo ya pagado; reanudar solo funciona si el periodo no ha terminado; swap cambia el plan y factura la diferencia de forma prorrateada. Con esos tres métodos cubres el 90% de la gestión de una suscripción.
Periodo de gracia y estados (past_due, unpaid)
Cuando un cargo falla, Stripe marca la suscripción como past_due y Cashier la cancela tras un periodo de gracia si el cliente no actualiza su método de pago. Puedes consultar el estado con pastDue() o unpaid() sobre la suscripción y ofrecer un formulario para actualizar la tarjeta antes de perder al cliente.
Métodos de pago y cobros únicos
Las suscripciones no cubren todos los casos: a veces necesitas cobrar un pago puntual o guardar varias tarjetas por cliente.
Por qué el método por defecto no sirve para cobros únicos
Hay una limitación real de Stripe que Cashier hereda: el método de pago por defecto de un customer solo puede usarse para facturación y para crear suscripciones nuevas; no puede usarse para cobros únicos. Para un cargo puntual necesitas que el cliente elija un método en una sesión de Checkout o en un modal de pago.
Añadir y eliminar métodos de pago
$user->addPaymentMethod($paymentMethodId);
$paymentMethod->delete();addPaymentMethod guarda el método como disponible sin cobrar nada; delete lo elimina de la cuenta del cliente. Ambos métodos operan sobre instancias de PaymentMethod y cubren la gestión de tarjetas sin que los datos sensibles pasen por tu servidor.
Facturas: listarlas, previsualizarlas y descargarlas en PDF
Cashier trata cada cargo como una factura con su PDF asociado. Listarlas es directo:
foreach ($user->invoices() as $invoice) {
echo $invoice->date()->toFormattedDateString();
}Para la descarga en PDF se usa downloadInvoice, que genera el archivo en memoria y lo devuelve como respuesta de descarga; el nombre de archivo personalizado se sufija automáticamente con .pdf:
return $user->downloadInvoice($invoice->id, [
'vendor' => 'Tu Empresa',
'product' => 'Suscripción Pro',
]);Es el flujo habitual en apps Laravel con Stripe: lista de facturas en el panel de usuario y botón de descarga por factura, sin generar los PDFs a mano.
Probar pagos sin dinero real: Stripe CLI y webhooks en local
Stripe CLI es la pieza que falta en desarrollo: reenvía los webhooks de Stripe a tu máquina local. Instala el CLI, inicia sesión con tu cuenta y lanza:
stripe listen --forward-to http://localhost:8000/stripe/webhookEl comando imprime un secret de webhook que añades al .env como STRIPE_WEBHOOK_SECRET. Desde ese momento, cada pago de prueba dispara los eventos en tu app como si fuera producción, y puedes probar el flujo completo: suscripción, cargo fallido, cancelación y reanudación, todo con tarjetas de prueba.
Conclusión
Con Laravel Cashier, cobrar una suscripción en Laravel 13 deja de ser un proyecto: se instala el paquete, se añade el trait Billable, se redirige a Checkout y se escucha el webhook. El resto —cancelaciones, cambios de plan, facturas en PDF— son métodos ya resueltos por el paquete. Si además necesitas traducir tu panel de facturación, nuestra guía de localización en Laravel 13 te muestra cómo hacerlo. Sigue leyendo el blog para más tutoriales de Laravel 13.