Subscription-based business models are more popular than ever. From SaaS applications to membership sites, recurring payments are the foundation of many successful businesses. But implementing subscription management can be complex—unless you're using Laravel.
Laravel is perfect for subscription management because it provides built-in tools and features that make handling recurring payments, subscription lifecycles, and billing incredibly easy. In this guide, we'll explore why Laravel is the ideal framework for subscriptions and show you the easiest way to implement subscription management.
Understanding Subscription Models
Before diving into implementation, let's understand what subscription management involves:
Recurring Billing
- Automatic monthly or annual charges
- Payment method management
- Failed payment handling
- Invoice generation
Subscription Tiers
- Multiple subscription plans (Basic, Pro, Enterprise)
- Feature access based on plan
- Plan upgrades and downgrades
- Proration for plan changes
Trial Periods
- Free trial periods
- Trial expiration handling
- Conversion tracking
Subscription Lifecycle
- Subscription creation
- Renewals
- Cancellations
- Reactivation
Laravel Cashier: The Easiest Solution
Laravel Cashier is Laravel's official package for managing subscription billing with Stripe and Paddle. It provides the easiest way to handle subscriptions in Laravel applications.
What is Laravel Cashier?
Laravel Cashier provides an expressive, fluent interface to Stripe's and Paddle's subscription billing services. It handles almost all of the boilerplate subscription billing code you don't want to write.
Why It's the Easiest Way
- Built-in Features: Handles subscriptions, coupons, invoices, and more out of the box
- Simple API: Expressive, fluent interface that's easy to use
- Automatic Webhooks: Handles Stripe webhooks automatically
- Database Integration: Seamlessly integrates with Laravel's Eloquent ORM
- Event System: Built-in events for subscription lifecycle
- Well Documented: Excellent documentation and examples
Why Laravel is Perfect for Subscription Management
Laravel is the perfect fit for subscription management for several reasons:
1. Built-in Subscription Support
Laravel Cashier is an official Laravel package, meaning it's:
- Maintained by the Laravel team
- Regularly updated
- Well-tested and reliable
- Integrated with Laravel's ecosystem
2. Eloquent ORM for Subscription Data
Laravel's Eloquent ORM makes working with subscription data easy:
// Check if user has active subscription
if ($user->subscribed('default')) {
// User has active subscription
}
// Get subscription details
$subscription = $user->subscription('default');
// Check subscription status
if ($user->subscription('default')->active()) {
// Subscription is active
}
// Access subscription properties
$subscription->stripe_status;
$subscription->stripe_price;
$subscription->trial_ends_at;
3. Event System for Subscription Lifecycle
Laravel's event system makes it easy to handle subscription events:
// Listen to subscription events
use Laravel\Cashier\Events\WebhookReceived;
Event::listen(WebhookReceived::class, function ($event) {
if ($event->payload['type'] === 'customer.subscription.created') {
// Handle new subscription
}
if ($event->payload['type'] === 'customer.subscription.deleted') {
// Handle canceled subscription
}
});
// Or use Cashier's built-in events
use Laravel\Cashier\Events\SubscriptionCreated;
use Laravel\Cashier\Events\SubscriptionCanceled;
Event::listen(SubscriptionCreated::class, function ($event) {
// Send welcome email
// Grant access to features
});
Event::listen(SubscriptionCanceled::class, function ($event) {
// Revoke access
// Send cancellation email
});
4. Queue System for Background Processing
Laravel's queue system is perfect for subscription-related background tasks:
- Processing webhooks asynchronously
- Sending subscription emails
- Updating user access levels
- Generating invoices
5. Easy Integration with Payment Gateways
Laravel Cashier integrates seamlessly with Stripe and Paddle, handling:
- Payment method management
- Webhook processing
- Invoice generation
- Payment failures
Setting Up Laravel Cashier
1. Installation
// Install Laravel Cashier
composer require laravel/cashier
// Publish migrations
php artisan vendor:publish --tag="cashier-migrations"
// Run migrations
php artisan migrate
2. Configuration
// Add to .env
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-webhook-secret
// In config/services.php (already configured)
'stripe' => [
'model' => App\Models\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
'webhook' => [
'secret' => env('STRIPE_WEBHOOK_SECRET'),
'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
],
],
3. Update User Model
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
// That's it! Cashier adds all subscription methods
}
Creating Subscriptions
1. Subscription Plans
First, create subscription plans in Stripe, then reference them in your code:
// Create subscription with payment method
$user->newSubscription('default', 'price_monthly')
->create($paymentMethod);
// Create subscription with trial
$user->newSubscription('default', 'price_monthly')
->trialDays(14)
->create($paymentMethod);
// Create subscription with coupon
$user->newSubscription('default', 'price_monthly')
->withCoupon('discount-code')
->create($paymentMethod);
2. Multiple Subscription Types
You can have multiple subscription types per user:
// Main subscription
$user->newSubscription('main', 'price_monthly')->create($paymentMethod);
// Add-on subscription
$user->newSubscription('addon', 'price_addon')->create($paymentMethod);
// Check specific subscription
if ($user->subscription('main')->active()) {
// Main subscription is active
}
3. Subscription Quantities
// Subscription with quantity (e.g., team size)
$user->newSubscription('default', 'price_monthly')
->quantity(5) // 5 seats
->create($paymentMethod);
Managing Subscriptions
1. Updating Subscriptions
// Swap to different plan
$user->subscription('default')->swap('price_annual');
// Update quantity
$user->subscription('default')->incrementQuantity(2);
// Update payment method
$user->updateDefaultPaymentMethod($paymentMethod);
2. Canceling Subscriptions
// Cancel immediately
$user->subscription('default')->cancel();
// Cancel at end of billing period
$user->subscription('default')->cancelNow();
// Resume canceled subscription
$user->subscription('default')->resume();
3. Checking Subscription Status
// Check if subscribed
if ($user->subscribed('default')) {
// User has subscription
}
// Check if on trial
if ($user->onTrial('default')) {
// User is on trial
}
// Check if canceled
if ($user->subscription('default')->canceled()) {
// Subscription is canceled
}
// Check if on grace period
if ($user->subscription('default')->onGracePeriod()) {
// Still has access until period ends
}
Handling Subscription Events
1. Webhook Setup
Laravel Cashier automatically handles Stripe webhooks:
// Route for webhooks (in routes/web.php)
Route::post(
'stripe/webhook',
[\Laravel\Cashier\Http\Controllers\WebhookController::class, 'handleWebhook']
)->name('cashier.webhook');
// Configure in Stripe dashboard:
// Webhook URL: https://yourdomain.com/stripe/webhook
// Events to listen: customer.subscription.*, invoice.*, etc.
2. Subscription Lifecycle Events
// Listen to subscription events
use Laravel\Cashier\Events\SubscriptionCreated;
use Laravel\Cashier\Events\SubscriptionUpdated;
use Laravel\Cashier\Events\SubscriptionCanceled;
Event::listen(SubscriptionCreated::class, function ($event) {
$subscription = $event->subscription;
$user = $subscription->user;
// Grant access to features
// Send welcome email
// Update user role
});
Event::listen(SubscriptionCanceled::class, function ($event) {
$subscription = $event->subscription;
$user = $subscription->user;
// Revoke access
// Send cancellation email
});
3. Payment Failures
// Handle failed payments
use Laravel\Cashier\Events\PaymentActionRequired;
Event::listen(PaymentActionRequired::class, function ($event) {
$invoice = $event->invoice;
$user = $invoice->user;
// Notify user of payment issue
// Send email with payment link
});
// Retry failed payment
$user->invoice()->pay();
Subscription Features
1. Coupons and Discounts
// Apply coupon to subscription
$user->newSubscription('default', 'price_monthly')
->withCoupon('SAVE20')
->create($paymentMethod);
// Apply coupon to existing subscription
$user->subscription('default')->applyCoupon('SAVE20');
2. Metered Billing
For usage-based billing:
// Report usage for metered billing
$user->subscription('default')->reportUsage(100); // 100 units used
// Get usage for current period
$usage = $user->subscription('default')->usage();
3. Invoice Management
// Get user invoices
$invoices = $user->invoices();
// Download invoice
return $user->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);
// Get upcoming invoice
$upcomingInvoice = $user->upcomingInvoice();
User Experience
1. Subscription Management UI
Create a user-friendly interface for managing subscriptions:
- View current subscription
- Upgrade/downgrade plans
- Update payment method
- View invoices
- Cancel subscription
2. Customer Portal
Stripe provides a hosted customer portal, or you can build your own:
// Redirect to Stripe customer portal
return $user->redirectToBillingPortal();
// Or build custom portal using Cashier methods
// Check subscription status
// Display plans
// Handle upgrades/downgrades
Best Practices
1. Error Handling
try {
$user->newSubscription('default', 'price_monthly')
->create($paymentMethod);
} catch (\Laravel\Cashier\Exceptions\IncompletePayment $e) {
// Payment requires additional action
return redirect()->route('payment.required', [
'payment' => $e->payment->id
]);
} catch (\Exception $e) {
// Handle other errors
return back()->withErrors(['error' => $e->getMessage()]);
}
2. Webhook Security
- Always verify webhook signatures
- Use HTTPS for webhook endpoints
- Validate webhook data
- Handle idempotency
3. Subscription Testing
Use Stripe test mode for development:
- Test subscription creation
- Test plan changes
- Test cancellations
- Test payment failures
- Test webhook handling
Real-World Examples
Example 1: SaaS Application
A SaaS application with multiple subscription tiers:
// Check user access based on subscription
if ($user->subscribed('default')) {
$subscription = $user->subscription('default');
if ($subscription->stripe_price === 'price_pro') {
// Pro features
} elseif ($subscription->stripe_price === 'price_enterprise') {
// Enterprise features
}
}
// Middleware to protect subscription routes
class SubscriptionMiddleware
{
public function handle($request, Closure $next)
{
if (!$request->user()->subscribed('default')) {
return redirect()->route('subscription.required');
}
return $next($request);
}
}
Example 2: Membership Site
A membership site with recurring monthly payments:
// Grant access on subscription
Event::listen(SubscriptionCreated::class, function ($event) {
$user = $event->subscription->user;
$user->assignRole('member');
Mail::to($user)->send(new WelcomeEmail());
});
// Revoke access on cancellation
Event::listen(SubscriptionCanceled::class, function ($event) {
$user = $event->subscription->user;
$user->removeRole('member');
});
Alternative Solutions
Other Payment Gateways
While Laravel Cashier focuses on Stripe and Paddle, you can integrate other gateways:
- PayPal Subscriptions (custom implementation)
- Braintree (custom implementation)
- Other gateways with custom code
Custom Subscription Implementation
For more control, you can build custom subscription logic, but Laravel Cashier is usually the easiest and most reliable solution.
Why Laravel Makes Subscription Management Easy
Laravel is perfect for subscription management because:
- Official Package: Laravel Cashier is maintained by Laravel team
- Simple API: Expressive methods make subscription code readable
- Built-in Features: Handles webhooks, invoices, and events automatically
- Database Integration: Seamless Eloquent integration
- Event System: Easy to hook into subscription lifecycle
- Queue Support: Background processing for subscription tasks
- Testing Support: Easy to test subscription logic
- Documentation: Excellent documentation and examples
Conclusion
Laravel subscriptions are incredibly easy to implement thanks to Laravel Cashier. The framework provides all the tools you need to handle recurring payments, subscription management, and billing—making it the easiest way to build subscription-based applications.
Whether you're building a SaaS application, membership site, or any subscription-based service, Laravel is the perfect fit for easy subscription management. Laravel Cashier handles the complexity, so you can focus on building your application.
Working with experienced Laravel developers who understand subscription management can help you implement a robust, reliable subscription system quickly and efficiently.
If you need help implementing subscription management with Laravel, our team specializes in Laravel subscription systems. We can help you set up Laravel Cashier, integrate payment gateways, and build subscription management features that make recurring billing easy.