Laravel Stripe Integration
Stripe in Laravel is easy to demo and easy to get subtly wrong in production.
Authentication and data flow
Inbound: Stripe signs webhooks. Verify the signature with the endpoint secret for that environment. Do not share test and live secrets. Process the event on a queue; return 2xx quickly.
Outbound: API keys belong in env, not in Git. Prefer restricted keys where the product allows. The Laravel app is not the source of truth for “has money moved” — Stripe is. Your tables should store your entitlement state derived from events, not a guess from the last browser request.
Common failure modes
- Webhook endpoint still pointing at a developer’s ngrok.
- Duplicate events creating duplicate entitlements because the handler is not idempotent on
event.id. checkout.session.completedhandled butinvoice.paid/ subscription deletion ignored.- Customer created in Stripe with a personal email, then the business cannot access the account.
Example pattern (characterisation, not a copy-paste product)
// Verify, then queue. Never do entitlement work in the HTTP request.
Route::post('/stripe/webhook', StripeWebhookController::class);
The controller’s only job is verify + persist payload + dispatch job. The job checks it has not processed evt_... before.
Stripe’s own webhook docs: stripe.com/docs/webhooks.
Questions that usually come up
Do you use Cashier?
When it fits. Cashier is not mandatory, and it is not a substitute for webhook handling and a clear billing state machine.
Can you take over a half-finished Stripe integration?
Yes. That is usually a rescue of the billing paths plus tests, not a new checkout UI.
Qualification
Discuss your Laravel project
Name, work email, and a short description of the application is enough. No discovery call theatre before I know whether I can actually help.
- UK businesses with a real Laravel (or legacy PHP) application
- Build, support, rescue, upgrade or integration work
- Reply from Oliver Burton, usually within one working day