关于 laravel-billing
这项技能介绍如何用 Laravel Cashier 和 Stripe 或 Paddle 实现计费,面向 Laravel 开发者。内容涵盖订阅、支付流程、安全处理及 SaaS 计费模式,也包括 FuseCore 集成。
主要功能
- 01Stripe 与 Paddle 选择指引
- 02订阅生命周期与试用管理
- 03Webhook 处理与签名验证
- 04结账、发票和支付方式
- 05按用量、团队及套餐计费
- 06FuseCore 集成参考与模板
适用场景
- 01在 Laravel 应用中实现订阅
- 02安全处理支付 Webhook
- 03添加按用量或按席位计费
- 04处理失败付款并按套餐控制功能
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ fusengine/ agents --skill laravel-billing安装后在 Claude Code 中输入/laravel-billing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/checkout.mddunning.mdfeature-flags.mdinvoices.mdmetered-billing.mdpaddle.mdpayment-methods.mdstripe.mdsubscriptions.mdteam-billing.mdtesting.mdwebhooks.mdreferences/templates/BillingRoutes.php.mdCheckoutController.php.mdDunningService.php.mdFeatureFlags.php.mdInvoiceController.php.mdMeteredBillingController.php.mdSubscriptionController.php.mdSubscriptionTest.php.mdTeamBillable.php.mdUserBillable.php.mdWebhookController.php.md详细介绍
涵盖 Laravel Cashier for Stripe 和 Paddle:如何在两者之间选择
(支付处理商还是名义商户、税务处理、费用)、订阅生命周期(创建、
切换、取消、恢复、试用期、宽限期)、Webhook 和签名验证、发票、支付
方式、结账/客户门户、按量计费、团队/按席位计费、催缴(失败付款
补救),以及基于 Pennant 的计划功能标志。包含 FuseCore
模块化项目集成。对于多供应商/市场拆分付款,请改用
laravel-stripe-connect。
Laravel 账单(Cashier)
Agent 工作流(必须遵循)
在进行任何实现之前,并行启动 3 个 Agent,每个 Agent 调用各一次,并指定 name:
- fuse-ai-pilot:explore-codebase - 检查现有账单设置和 User 模型
- fuse-ai-pilot:research-expert - 通过 Context7 核实最新 Cashier 文档
- mcp__context7__query-docs - 查询特定模式(Stripe/Paddle)
实现完成后,运行 fuse-ai-pilot:sniper 进行验证。
概览
Laravel Cashier 提供基于 Stripe 或 Paddle 的订阅账单功能。根据需求选择:
| 提供商 | 包 | 最适合 |
|---|---|---|
| Stripe | laravel/cashier | 完全控制、高交易量、复杂账单 |
| Paddle | laravel/cashier-paddle | 税务处理、合规、全球销售 |
主要区别:名义商户与支付处理商
| 方面 | Stripe | Paddle |
|---|---|---|
| 类型 | 支付处理商 | 名义商户 |
| 税费 | 由你管理(或使用 Stripe Tax) | Paddle 自动管理 |
| 发票 | 你的公司名称 | Paddle + 你的名称 |
| 合规 | 由你负责 | 由 Paddle 处理 |
| 费用 | 约 2.9% + $0.30 | 约 5% + $0.50(全包) |
关键规则
- 使用 Webhook - 切勿依赖客户端确认
- 处理宽限期 - 在订阅结束前允许访问
- 切勿存储银行卡详情 - 使用支付令牌/支付方式
- 使用测试密钥进行测试 - 始终在上线前测试
- 验证 Webhook 签名 - 防止伪造攻击
- 处理未完成的付款 - 3D Secure 需要用户操作
架构
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 集成
在 FuseCore 项目中处理账单时,请遵循模块化结构:
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 账单检查清单
- 账单代码位于
/FuseCore/Billing/模块中 - User 模型(位于
/FuseCore/User/)使用 Billable trait - Webhook 路由位于
/FuseCore/Billing/Routes/web.php - 通过
preventRequestForgery(except: [...])将 Webhook 从 CSRF 检查中排除(L13PreventRequestForgery) - 在
module.json中声明"User"依赖项
→ 完整的模块模式请参阅 fusecore skill。
决策指南
Stripe 与 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
订阅与一次性付款
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
核心概念
| 概念 | 说明 | 参考 |
|---|---|---|
| 可计费 | 为模型启用账单功能的 trait | stripe.md |
| 订阅 | 循环计费周期 | subscriptions.md |
| 价格 ID | Stripe/Paddle 价格标识符 | stripe.md |
| 宽限期 | 取消后仍可访问的时段 | subscriptions.md |
| Webhook | 服务器到服务器的付款通知 | webhooks.md |
| 客户门户 | 自助式账单管理 | checkout.md |
参考指南
概念(原因与架构)
| 主题 | 参考资料 | 适用场景 |
|---|---|---|
| Stripe Cashier | stripe.md | 设置和配置 Stripe |
| Paddle Cashier | paddle.md | 设置 Paddle、了解差异 |
| 订阅 | subscriptions.md | 创建、取消、更换、暂停 |
| Webhook | webhooks.md | Webhook 安全、处理 |
| 发票 | invoices.md | 生成 PDF、收据 |
| 支付方式 | payment-methods.md | 卡片、电子钱包、更新 |
| 结账 | checkout.md | 托管结账、门户 |
| 测试 | testing.md | 测试卡、Webhook 测试 |
高级 SaaS 功能
| 主题 | 参考资料 | 适用场景 |
|---|---|---|
| 按用量计费 | metered-billing.md | 基于用量定价(API、存储) |
| 团队计费 | team-billing.md | 组织计费、按席位计费 |
| 催收 | dunning.md | 追回失败的付款 |
| 功能标志 | feature-flags.md | 基于方案的功能访问 |
模板(完整代码)
| 模板 | 使用场景 |
|---|---|
| UserBillable.php.md | 带有 Billable trait 的用户模型 |
| SubscriptionController.php.md | 订阅 CRUD 操作 |
| WebhookController.php.md | 自定义 Webhook 处理 |
| CheckoutController.php.md | Stripe Checkout + Portal |
| InvoiceController.php.md | 下载发票 |
| BillingRoutes.php.md | 完整路由定义 |
| SubscriptionTest.php.md | 计费 Pest 测试 |
| MeteredBillingController.php.md | 用量跟踪与报告 |
| TeamBillable.php.md | 带有席位管理的团队模型 |
| DunningService.php.md | 自动化付款追回 |
| FeatureFlags.php.md | Laravel Pennant 按方案配置功能 |
快速参考
检查订阅状态
// 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();
创建订阅
// Simple subscription
$user->newSubscription('default', 'price_monthly')
->create($paymentMethodId);
// With trial
$user->newSubscription('default', 'price_monthly')
->trialDays(14)
->create($paymentMethodId);
管理订阅
$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();
计费门户
// Redirect to customer portal (Stripe)
return $user->redirectToBillingPortal(route('dashboard'));
// Get portal URL
$url = $user->billingPortalUrl(route('dashboard'));
最佳实践
应该做
- 使用 Webhook 确认付款
- 为已取消的订阅设置宽限期
- 设置 Webhook 签名验证
- 处理
IncompletePayment异常 - 使用 Stripe CLI 在本地测试
- 定期清理旧数据
不应该做
- 信任客户端付款确认
- 存储银行卡号(PCI 合规)
- 跳过 Webhook 验证
- 忽略付款失败的 Webhook
- 忘记处理 3D Secure
- 将价格硬编码(使用 env 或配置)
Laravel 13 注意事项
Cashier Stripe 16.x(当前版本为 16.8)和 Cashier Paddle 2.x(当前版本为 2.8)兼容 Laravel 13。注意事项:
- Webhook:新的 [[laravel-auth]]
PreventRequestForgeryCSRF 保护必须通过preventRequestForgery(except: [...])将 Webhook 路由(stripe/webhook、paddle/webhook)排除在外 cache.serializable_classes(L13 中默认为false):如果缓存 Cashier 对象,请明确列出类- PHP:Cashier 支持 PHP 8.1+,但 Laravel 13 要求 PHP 版本至少为 8.3
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->preventRequestForgery(except: [
'stripe/*', 'paddle/*',
]);
})
评论
支持 Markdown