mcpField
L
laravel-billing

laravel-billing

github.com/fusengineDevelopment3457 installsUpdated 2w ago
Repository

About laravel-billing

A Laravel Cashier skill for implementing billing with Stripe or Paddle. It covers subscription operations, payment workflows, security, and SaaS billing patterns, including FuseCore integration.

Key features

  1. 01Stripe and Paddle selection guidance
  2. 02Subscription lifecycle and trials
  3. 03Webhook handling and signature checks
  4. 04Checkout, invoices, and payment methods
  5. 05Metered, team, and plan-based billing
  6. 06FuseCore integration references and templates

Use cases

  1. 01Implementing subscriptions in a Laravel app
  2. 02Handling payment webhooks securely
  3. 03Adding usage-based or per-seat billing
  4. 04Recovering failed payments and gating plan features

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/fusengine/agents --skill laravel-billing

After installing, type/laravel-billingin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
checkout.md
dunning.md
feature-flags.md
invoices.md
metered-billing.md
paddle.md
payment-methods.md
stripe.md
subscriptions.md
team-billing.md
testing.md
webhooks.md
references/templates/
BillingRoutes.php.md
CheckoutController.php.md
DunningService.php.md
FeatureFlags.php.md
InvoiceController.php.md
MeteredBillingController.php.md
SubscriptionController.php.md
SubscriptionTest.php.md
TeamBillable.php.md
UserBillable.php.md
WebhookController.php.md

Details

From the project README
Covers Laravel Cashier for Stripe and Paddle: choosing between the two (payment processor vs merchant-of-record, tax handling, fees), subscription lifecycle (create, swap, cancel, resume, trials, grace periods), webhooks and signature verification, invoices, payment methods, checkout/customer portal, metered/usage-based billing, team/per-seat billing, dunning (failed-payment recovery), and Pennant-based feature flags per plan. Includes FuseCore modular-project integration. For multi-vendor/marketplace split payments, see laravel-stripe-connect instead.

Laravel Billing (Cashier)

Agent Workflow (MANDATORY)

Before ANY implementation, spawn 3 agents in parallel, one Agent call each with a name:

  1. fuse-ai-pilot:explore-codebase - Check existing billing setup, User model
  2. fuse-ai-pilot:research-expert - Verify latest Cashier docs via Context7
  3. mcp__context7__query-docs - Query specific patterns (Stripe/Paddle)

After implementation, run fuse-ai-pilot:sniper for validation.


Overview

Laravel Cashier provides subscription billing with Stripe or Paddle. Choose based on your needs:

ProviderPackageBest For
Stripelaravel/cashierFull control, high volume, complex billing
Paddlelaravel/cashier-paddleTax handling, compliance, global sales
Key Difference: MoR vs Payment Processor
AspectStripePaddle
TypePayment ProcessorMerchant of Record
TaxesYou manage (or Stripe Tax)Paddle manages automatically
InvoicesYour company namePaddle + your name
ComplianceYour responsibilityPaddle handles
Fees~2.9% + $0.30~5% + $0.50 (all-inclusive)

Critical Rules

  1. Use webhooks - Never rely on client-side confirmations
  2. Handle grace periods - Allow access until subscription ends
  3. Never store card details - Use payment tokens/methods
  4. Test with test keys - Always before production
  5. Verify webhook signatures - Prevent spoofing attacks
  6. Handle incomplete payments - 3D Secure requires user action

Architecture

app/
├── Http/
│   ├── Controllers/
│   │   └── Billing/              ← Billing controllers
│   │       ├── SubscriptionController.php
│   │       ├── CheckoutController.php
│   │       └── InvoiceController.php
│   └── Middleware/
│       └── EnsureSubscribed.php  ← Subscription check
├── Models/
│   └── User.php                  ← Billable trait
├── Listeners/
│   └── StripeEventListener.php   ← Webhook handling
└── Services/
    └── BillingService.php        ← Business logic

config/
├── cashier.php                   ← Stripe/Paddle config
└── services.php                  ← API keys

routes/
└── web.php                       ← Webhook routes (excluded from CSRF)

FuseCore Integration

When working in a FuseCore project, billing follows the modular structure:

FuseCore/
├── Core/                         # Infrastructure (priority 0)
│   └── App/Contracts/
│       └── BillingServiceInterface.php  ← Billing contract
│
├── User/                         # Auth module (existing)
│   └── App/Models/User.php       ← Add Billable trait here
│
├── Billing/                      # Billing module (new)
│   ├── App/
│   │   ├── Http/
│   │   │   ├── Controllers/
│   │   │   │   ├── SubscriptionController.php
│   │   │   │   ├── CheckoutController.php
│   │   │   │   └── WebhookController.php
│   │   │   └── Middleware/
│   │   │       └── EnsureSubscribed.php
│   │   ├── Listeners/
│   │   │   └── HandleWebhookEvents.php
│   │   └── Services/
│   │       └── BillingService.php
│   ├── Config/
│   │   └── cashier.php           ← Module-level config
│   ├── Database/Migrations/
│   ├── Routes/
│   │   ├── web.php               ← Webhooks (no CSRF)
│   │   └── api.php               ← Subscription management
│   └── module.json               # dependencies: ["User"]
FuseCore Billing Checklist
  • Billing code in /FuseCore/Billing/ module
  • Billable trait on User model in /FuseCore/User/
  • Webhook routes in /FuseCore/Billing/Routes/web.php
  • Exclude webhook from CSRF via preventRequestForgery(except: [...]) (L13 PreventRequestForgery)
  • Declare "User" dependency in module.json

→ See fusecore skill for complete module patterns.


Decision Guide

Stripe vs Paddle
Selling to businesses (B2B)? → Stripe
├── Need OAuth for third-party apps? → Stripe Connect
└── Selling to consumers (B2C) globally?
    ├── Want to handle taxes yourself? → Stripe + Stripe Tax
    └── Want tax compliance handled? → Paddle
Subscription vs One-Time
Recurring revenue? → Subscription
├── Fixed plans? → Single-price subscription
└── Usage-based? → Metered billing (Stripe) or quantity-based
Single purchase? → One-time charge
├── Digital product? → Checkout session
└── Service fee? → Direct charge

Key Concepts

ConceptDescriptionReference
BillableTrait that enables billing on a modelstripe.md
SubscriptionRecurring billing cyclesubscriptions.md
Price IDStripe/Paddle price identifierstripe.md
Grace PeriodTime after cancellation with accesssubscriptions.md
WebhookServer-to-server payment notificationswebhooks.md
Customer PortalSelf-service billing managementcheckout.md

Reference Guide

Concepts (WHY & Architecture)
TopicReferenceWhen to Consult
Stripe Cashierstripe.mdStripe setup, configuration
Paddle Cashierpaddle.mdPaddle setup, differences
Subscriptionssubscriptions.mdCreate, cancel, swap, pause
Webhookswebhooks.mdWebhook security, handling
Invoicesinvoices.mdPDF generation, receipts
Payment Methodspayment-methods.mdCards, wallets, updates
Checkoutcheckout.mdHosted checkout, portal
Testingtesting.mdTest cards, webhook testing
Advanced SaaS Features
TopicReferenceWhen to Consult
Metered Billingmetered-billing.mdUsage-based pricing (API, storage)
Team Billingteam-billing.mdOrganization billing, per-seat
Dunningdunning.mdFailed payment recovery
Feature Flagsfeature-flags.mdPlan-based feature access
Templates (Complete Code)
TemplateWhen to Use
UserBillable.php.mdUser model with Billable trait
SubscriptionController.php.mdCRUD subscription operations
WebhookController.php.mdCustom webhook handling
CheckoutController.php.mdStripe Checkout + Portal
InvoiceController.php.mdInvoice download
BillingRoutes.php.mdComplete route definitions
SubscriptionTest.php.mdPest tests for billing
MeteredBillingController.php.mdUsage tracking and reporting
TeamBillable.php.mdTeam model with seat management
DunningService.php.mdPayment recovery automation
FeatureFlags.php.mdLaravel Pennant per-plan features

Quick Reference

Check Subscription Status
// Has active subscription?
$user->subscribed('default');

// Subscribed to specific price?
$user->subscribedToPrice('price_premium', 'default');

// On trial?
$user->onTrial('default');

// Cancelled but still active?
$user->subscription('default')->onGracePeriod();
Create Subscription
// Simple subscription
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethodId);

// With trial
$user->newSubscription('default', 'price_monthly')
    ->trialDays(14)
    ->create($paymentMethodId);
Manage Subscription
$subscription = $user->subscription('default');

// Change plan
$subscription->swap('price_yearly');

// Cancel at period end
$subscription->cancel();

// Cancel immediately
$subscription->cancelNow();

// Resume cancelled subscription
$subscription->resume();
Billing Portal
// Redirect to customer portal (Stripe)
return $user->redirectToBillingPortal(route('dashboard'));

// Get portal URL
$url = $user->billingPortalUrl(route('dashboard'));

Best Practices

DO
  • Use webhooks for payment confirmation
  • Implement grace periods for cancelled subscriptions
  • Set up webhook signature verification
  • Handle IncompletePayment exceptions
  • Test with Stripe CLI locally
  • Prune old data regularly
DON'T
  • Trust client-side payment confirmations
  • Store card numbers (PCI compliance)
  • Skip webhook verification
  • Ignore failed payment webhooks
  • Forget to handle 3D Secure
  • Hardcode prices (use env or config)

Laravel 13 Notes

Cashier Stripe 16.x (current 16.8) and Cashier Paddle 2.x (current 2.8) are Laravel 13 compatible. Points to watch:

  • Webhooks: the new [[laravel-auth]] PreventRequestForgery CSRF protection must exclude webhook routes (stripe/webhook, paddle/webhook) via preventRequestForgery(except: [...])
  • cache.serializable_classes (default false in L13): list the classes explicitly if you cache Cashier objects
  • PHP: Cashier accepts PHP 8.1+, but Laravel 13 requires PHP 8.3 minimum
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->preventRequestForgery(except: [
        'stripe/*', 'paddle/*',
    ]);
})

Comments

Markdown supported