home / skills / fusengine / agents / laravel-billing

This skill helps you integrate Stripe and Paddle billing with Laravel Cashier, guiding subscription, invoices, and webhooks setup for robust payments.

npx playbooks add skill fusengine/agents --skill laravel-billing

Review the files below or copy the command above to add this skill to your agents.

Files (24)
SKILL.md
10.6 KB
---
name: laravel-billing
description: Integrate Stripe and Paddle payments with Laravel Cashier. Use when implementing subscriptions, invoices, payment methods, webhooks, or billing portals.
versions:
  laravel: "12.x"
  cashier-stripe: "16.x"
  cashier-paddle: "2.x"
  php: "8.4"
user-invocable: true
references: references/stripe.md, references/paddle.md, references/subscriptions.md, references/webhooks.md, references/invoices.md, references/payment-methods.md, references/testing.md, references/checkout.md, references/metered-billing.md, references/team-billing.md, references/dunning.md, references/feature-flags.md, references/templates/UserBillable.php.md, references/templates/SubscriptionController.php.md, references/templates/WebhookController.php.md, references/templates/CheckoutController.php.md, references/templates/InvoiceController.php.md, references/templates/BillingRoutes.php.md, references/templates/SubscriptionTest.php.md, references/templates/MeteredBillingController.php.md, references/templates/TeamBillable.php.md, references/templates/DunningService.php.md, references/templates/FeatureFlags.php.md
related-skills: laravel-auth, laravel-api, fusecore
---

# Laravel Billing (Cashier)

## Agent Workflow (MANDATORY)

Before ANY implementation, use `TeamCreate` to spawn 3 agents:

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:

| Provider | Package | Best For |
|----------|---------|----------|
| **Stripe** | `laravel/cashier` | Full control, high volume, complex billing |
| **Paddle** | `laravel/cashier-paddle` | Tax handling, compliance, global sales |

### Key Difference: MoR vs Payment Processor

| Aspect | Stripe | Paddle |
|--------|--------|--------|
| **Type** | Payment Processor | Merchant of Record |
| **Taxes** | You manage (or Stripe Tax) | Paddle manages automatically |
| **Invoices** | Your company name | Paddle + your name |
| **Compliance** | Your responsibility | Paddle 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 in `VerifyCsrfToken`
- [ ] Declare `"User"` dependency in `module.json`

→ See [fusecore skill](../fusecore/SKILL.md) 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

| Concept | Description | Reference |
|---------|-------------|-----------|
| **Billable** | Trait that enables billing on a model | [stripe.md](references/stripe.md) |
| **Subscription** | Recurring billing cycle | [subscriptions.md](references/subscriptions.md) |
| **Price ID** | Stripe/Paddle price identifier | [stripe.md](references/stripe.md) |
| **Grace Period** | Time after cancellation with access | [subscriptions.md](references/subscriptions.md) |
| **Webhook** | Server-to-server payment notifications | [webhooks.md](references/webhooks.md) |
| **Customer Portal** | Self-service billing management | [checkout.md](references/checkout.md) |

---

## Reference Guide

### Concepts (WHY & Architecture)

| Topic | Reference | When to Consult |
|-------|-----------|-----------------|
| **Stripe Cashier** | [stripe.md](references/stripe.md) | Stripe setup, configuration |
| **Paddle Cashier** | [paddle.md](references/paddle.md) | Paddle setup, differences |
| **Subscriptions** | [subscriptions.md](references/subscriptions.md) | Create, cancel, swap, pause |
| **Webhooks** | [webhooks.md](references/webhooks.md) | Webhook security, handling |
| **Invoices** | [invoices.md](references/invoices.md) | PDF generation, receipts |
| **Payment Methods** | [payment-methods.md](references/payment-methods.md) | Cards, wallets, updates |
| **Checkout** | [checkout.md](references/checkout.md) | Hosted checkout, portal |
| **Testing** | [testing.md](references/testing.md) | Test cards, webhook testing |

### Advanced SaaS Features

| Topic | Reference | When to Consult |
|-------|-----------|-----------------|
| **Metered Billing** | [metered-billing.md](references/metered-billing.md) | Usage-based pricing (API, storage) |
| **Team Billing** | [team-billing.md](references/team-billing.md) | Organization billing, per-seat |
| **Dunning** | [dunning.md](references/dunning.md) | Failed payment recovery |
| **Feature Flags** | [feature-flags.md](references/feature-flags.md) | Plan-based feature access |

### Templates (Complete Code)

| Template | When to Use |
|----------|-------------|
| [UserBillable.php.md](references/templates/UserBillable.php.md) | User model with Billable trait |
| [SubscriptionController.php.md](references/templates/SubscriptionController.php.md) | CRUD subscription operations |
| [WebhookController.php.md](references/templates/WebhookController.php.md) | Custom webhook handling |
| [CheckoutController.php.md](references/templates/CheckoutController.php.md) | Stripe Checkout + Portal |
| [InvoiceController.php.md](references/templates/InvoiceController.php.md) | Invoice download |
| [BillingRoutes.php.md](references/templates/BillingRoutes.php.md) | Complete route definitions |
| [SubscriptionTest.php.md](references/templates/SubscriptionTest.php.md) | Pest tests for billing |
| [MeteredBillingController.php.md](references/templates/MeteredBillingController.php.md) | Usage tracking and reporting |
| [TeamBillable.php.md](references/templates/TeamBillable.php.md) | Team model with seat management |
| [DunningService.php.md](references/templates/DunningService.php.md) | Payment recovery automation |
| [FeatureFlags.php.md](references/templates/FeatureFlags.php.md) | Laravel Pennant per-plan features |

---

## Quick Reference

### Check Subscription Status

```php
// 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

```php
// Simple subscription
$user->newSubscription('default', 'price_monthly')
    ->create($paymentMethodId);

// With trial
$user->newSubscription('default', 'price_monthly')
    ->trialDays(14)
    ->create($paymentMethodId);
```

### Manage Subscription

```php
$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

```php
// 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)

Overview

This skill integrates Stripe and Paddle payments with Laravel Cashier to implement subscriptions, invoices, payment methods, webhooks, and billing portals. It provides architecture patterns, FuseCore module guidance, and a decision guide to choose Stripe vs Paddle based on tax, compliance, and business model. The skill also prescribes an agent workflow to run discovery, research, and validation agents before and after implementation.

How this skill works

Before coding, the workflow spawns three agents to inspect the codebase, verify Cashier docs, and query provider-specific patterns. Implementation follows a modular billing module (controllers, services, listeners, routes) and wiring of the Billable trait on the User model. After implementation, a validation agent runs automated checks against webhook handling, subscription flows, and configuration.

When to use it

  • Adding subscription billing (recurring plans or meter-based pricing)
  • Implementing one-time checkout flows and invoice generation
  • Handling webhooks and server-to-server billing events
  • Choosing between Stripe (processor) and Paddle (merchant of record)
  • Integrating a customer billing portal for self-service management

Best practices

  • Always use webhooks for payment confirmations and verify signatures
  • Never store raw card details; use payment tokens/methods
  • Test thoroughly with test keys and Stripe CLI before production
  • Implement grace periods and handle incomplete payments (3D Secure)
  • Keep price IDs and keys out of code; use env or module-level config

Example use cases

  • Create subscription plans with trial periods and swap/cancel flows
  • Implement Stripe Checkout and redirect users to a billing portal
  • Process Paddle purchases where tax/compliance are handled by the provider
  • Build webhook listeners that update subscription state and invoices
  • Add metered billing endpoints to record usage for usage-based plans

FAQ

Which should I choose for global B2C sales?

Paddle is often better for global B2C because it handles taxes and compliance as merchant of record.

When is Stripe the better option?

Choose Stripe when you need full control, Stripe Connect, or advanced usage-based billing capabilities.

What are the mandatory workflow steps before coding?

Spawn three agents: explore-codebase, research-expert, and a docs query agent to inspect current billing setup and verify Cashier docs; run a validation agent after implementation.