Laravel Stripe Integration: Bookings, Subscriptions & Featured Listings

· 7 min read · Web Development

Payment integration is where many Laravel projects stall: test mode works, webhooks are forgotten, and production subscriptions silently fail. A proper laravel stripe integration covers Checkout or Cashier, webhook verification, idempotent handlers, and access control tied to subscription state—not just a “Pay” button.

This guide explains stripe checkout laravel flows, when to adopt laravel cashier, security requirements, and 2026 cost expectations. We reference our booking website guide (deposits and appointments), AI tools directory (featured listings), SaaS MVP guide, and Clean Pro Services booking platform for real patterns.

Stripe Checkout vs Laravel Cashier vs Payment Intents

Stripe Checkout (hosted page)

Fastest path: create a Checkout Session server-side, redirect user to Stripe, return to success/cancel URLs. Ideal for:

  • Single product or few plans
  • MVPs and one-time purchases
  • Founders who want Stripe to handle PCI and tax basics

Use the official stripe/stripe-php SDK or Laravel Cashier’s Checkout helpers.

Laravel Cashier

Best for recurring SaaS:

  • Subscriptions, trials, coupons, metered billing (with setup)
  • Customer Portal for self-service card updates
  • Billable User model and subscription tables out of the box

Payment Intents + custom UI

When you need embedded card fields on your site—marketplaces, complex upsells—more front-end work (Stripe Elements) and stricter PCI awareness. Budget extra dev and QA time.

End-to-End Checkout Flow (Laravel)

  1. User clicks purchase; Laravel creates Checkout Session with price_id, success/cancel URLs, and client_reference_id (your user ID)
  2. User pays on Stripe-hosted page
  3. Stripe sends checkout.session.completed webhook to your app
  4. Webhook handler verifies signature, idempotently grants access (role, credits, booking confirmation)
  5. Success page shows confirmation; never trust success URL alone without webhook

Booking sites often confirm appointments only after webhook or synchronous session retrieval—see service business booking guide.

Webhooks: Non-Negotiable Implementation

Register endpoint (e.g. /stripe/webhook), exclude from CSRF, verify with Stripe-Signature and webhook secret from dashboard.

  • Handle at minimum: checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted
  • Store processed event IDs to prevent double fulfillment
  • Queue heavy work (emails, provisioning) via Laravel jobs
  • Use Stripe CLI locally: stripe listen --forward-to localhost/stripe/webhook

Failed webhooks are the #1 cause of “I paid but my account is free” support tickets.

Mapping Payments to Application Access

Define clear states:

  • trialing — full or limited access until trial end
  • active — paid, feature flags on
  • past_due — grace period, banner + email
  • canceled — access until period end or immediate revoke per policy

Use middleware: EnsureSubscribed checks Cashier subscribed() or custom columns updated only by webhooks. Never grant lifetime access from checkout success redirect alone.

One-Time vs Subscription Pricing (2026 Patterns)

ModelStripe objectLaravel approach
One-time purchasePrice (mode: payment)Checkout Session
Monthly SaaSRecurring PriceCashier newSubscription
Featured listingOne-time or subscriptionCheckout + expiry job
Booking depositPaymentCheckout linked to appointment ID

Our AI directory combines free listings with paid featured slots—a common monetization path for directories without full SaaS complexity.

Testing Before Production

  • Use test API keys in .env; never commit secrets
  • Card numbers from Stripe docs (4242…) for success/failure scenarios
  • Test webhook delivery in staging with CLI or dashboard replay
  • Feature tests mocking Stripe SDK for unit paths; one integration test in test mode optional

Security & Compliance Checklist

  • Webhook secret in environment; rotate if leaked
  • HTTPS only in production
  • Do not log full card numbers (Stripe handles PAN)
  • Display refund policy and business name on receipts
  • For EU customers, consider VAT/tax with Stripe Tax when revenue justifies it

Integration Cost & Timeline

  • Simple Checkout (one product): $1,500–$4,000 within a larger build, 3–7 days
  • Cashier subscriptions + portal: $3,000–$8,000, 1–2 weeks
  • Marketplace Connect splits: $8,000–$25,000+ depending on onboarding KYC flows

Full project context: Laravel website cost 2026 and SaaS MVP guide.

Common Mistakes

  • Granting access on success URL only
  • Missing payment_failed handling → angry churn
  • Live keys in staging or vice versa
  • Not using Customer Portal for card updates
  • Hard-coding prices in Blade instead of Stripe Price IDs

Related Builds

Explore Clean Pro booking, AI tools directory, and SaaS MVP architecture for how Stripe fits real Laravel products.

Environment Variables Checklist

Never commit these; use Forge/Vapor secrets in production:

  • STRIPE_KEY and STRIPE_SECRET (test vs live per environment)
  • STRIPE_WEBHOOK_SECRET per endpoint (CLI tunnel uses different secret)
  • CASHIER_CURRENCY and model billable class configuration

Rotate keys if a contractor leaves with .env access. Stripe Dashboard lets you roll keys without deleting customers.

Refunds, Disputes, and Support Playbooks

Train support on Stripe Dashboard: partial refunds, subscription cancel at period end vs immediate, and evidence upload for disputes. Laravel should mirror Stripe state—if you refund in Dashboard manually, run a one-off script or admin action to revoke access if policy requires it.

Stripe Customer Portal vs Custom Billing Pages

Enable Customer Portal for card updates and invoice history early. Custom “billing settings” pages are expensive to maintain. Many laravel stripe integration projects ship Portal in week one and add branded billing UI only when design demands it.

Multi-Currency and Tax (When to Add)

Start single currency (USD or your primary market). Add Stripe Tax or manual tax IDs when >15% of revenue crosses borders or accountants require it. Premature multi-currency UI confuses Checkout testing.

Logging and Alerting for Payments

  • Log webhook event type and ID (not full card data)
  • Alert Slack on webhook signature failures and job failures after 3 retries
  • Weekly report: new MRR, failed payments, churn count from Cashier tables

Code Organization Tips

Keep Stripe logic out of controllers: dedicated listeners or invokable jobs per event type. Name jobs HandleCheckoutSessionCompleted rather than one 400-line webhook method. Use Stripe’s idempotency keys on API calls that create charges from your side (marketplaces).

Stripe Checkout Session Options Worth Setting

  • customer_email or existing Stripe customer ID for repeat buyers
  • allow_promotion_codes when running launch campaigns
  • billing_address_collection if invoices require it
  • success_url with session ID placeholder for optional client-side thank-you personalization—still confirm via webhook

For stripe checkout laravel implementations, store the Checkout Session ID on your local order row to reconcile support tickets.

Sandbox vs Production Cutover

Clone production-like data on staging with test keys. Run through subscribe, upgrade, cancel, and card decline flows. Swap keys in production during low-traffic window; replay missed webhooks from Stripe Dashboard if any downtime occurred during DNS or deploy.

Subscriptions: Trials, Proration, and Plan Changes

Cashier handles trial ending webhooks—gate features until subscription('default')->active(). Document whether upgrades are immediate with proration or at period end; mismatched expectations create refund requests. When adding plans later, create new Stripe Price IDs rather than editing prices in place (breaks historical reporting).

Frequently Asked Questions

Should I use Stripe Checkout or Laravel Cashier?

Use Checkout for fast one-time or simple subscription MVPs; use Cashier when you need ongoing subscription management, Customer Portal, and Laravel-native billable users.

How do I test Stripe webhooks locally with Laravel?

Run Stripe CLI to forward events to your local webhook route, use test keys in .env, and verify signatures with the webhook secret.

Why did my user pay but not get access?

Usually the webhook failed, was not registered for the event type, or access was tied to the redirect instead of webhook-confirmed payment state.

How much does Laravel Stripe integration cost?

Simple Checkout is often $1,500–$4,000 as part of a project; full Cashier SaaS billing commonly adds $3,000–$8,000 in 2026 agency estimates.

Need a production Laravel build?

We ship gaming communities with Discord login, Livewire admin panels, booking systems, directories, and SEO-ready launches.

Request a project estimate →

Tagged: Laravel Booking System