Skip to content

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.completed handled but invoice.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

Server-side validated. Used only to reply about this enquiry. See the privacy policy.