关于 subscriptions-best-practices
PayKit 订阅最佳实践技能,指导开发者使用统一的 subscribe() 处理订阅状态转换、结账和账单管理。内容涵盖客户端与服务端用法、状态读取、Stripe Webhook 和客户门户。
主要功能
- 01按当前状态处理订阅变更
- 02支持升级、降级、取消与恢复
- 03提供客户端和服务端调用示例
- 04说明读取订阅状态与结账跳转
- 05涵盖 Webhook 和客户门户
适用场景
- 01为用户开通或变更订阅计划
- 02将订阅状态同步到应用
- 03引导用户完成付款结账
- 04允许客户管理付款方式与发票
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ getpaykit/ skills --skill subscriptions-best-practices安装后在 Claude Code 中输入/subscriptions-best-practices确认已加载。
详细介绍
订阅
PayKit 使用一个 subscribe() 方法处理所有订阅变更。
subscribe()
const result = await paykit.subscribe({
customerId: "user_123",
planId: "pro",
successUrl: "https://example.com/billing?success=true",
cancelUrl: "https://example.com/billing",
})
参数
| 参数 | 必填 | 说明 |
|---|---|---|
customerId | 是 | 你应用的用户 ID |
planId | 是 | 目标套餐 ID(类型安全) |
successUrl | 是 | 结账成功后重定向到的地址 |
cancelUrl | 否 | 用户取消结账时重定向到的地址 |
forceCheckout | 否 | 始终重定向到结账页面,即使已有支付方式 |
返回值
interface SubscribeResult {
paymentUrl: string | null
invoice?: {
providerInvoiceId: string
hostedUrl: string | null
currency: string
totalAmount: number
status: string | null
}
requiredAction?: {
type: string
paymentIntentId?: string
clientSecret?: string
} | null
}
变更语义
subscribe() 会根据客户的当前状态确定正确的操作:
| 当前状态 | 目标 | 行为 |
|---|---|---|
| 无订阅 | 免费套餐 | 立即启用 |
| 无订阅 | 付费套餐,无支付方式 | 返回 Stripe Checkout 的 paymentUrl |
| 无订阅 | 付费套餐,已有支付方式 | 直接创建订阅 |
| 使用免费套餐 | 付费套餐 | 通过结账或直接创建订阅 |
| 使用付费套餐 | 更高价套餐(同一组) | 升级:立即切换 |
| 使用付费套餐 | 更低价套餐(同一组) | 降级:安排在周期结束时生效 |
| 使用付费套餐 | 免费套餐(同一组) | 取消:安排在周期结束时生效 |
| 待取消 | 同一套餐 | 恢复:清除取消操作 |
| 待降级 | 当前套餐 | 恢复:取消预定的变更 |
| 使用当前套餐 | 同一套餐,无待处理变更 | 无操作 |
服务端用法
// New subscription (may require checkout)
const { paymentUrl } = await paykit.subscribe({
customerId: "user_123",
planId: "pro",
successUrl: "/billing?success=true",
})
if (paymentUrl) {
// Redirect user to Stripe Checkout
redirect(paymentUrl)
}
// Upgrade (immediate, no checkout needed)
await paykit.subscribe({
customerId: "user_123",
planId: "enterprise",
successUrl: "/billing",
})
// Downgrade (scheduled for period end)
await paykit.subscribe({
customerId: "user_123",
planId: "free",
successUrl: "/billing",
})
// Resume a pending cancellation
await paykit.subscribe({
customerId: "user_123",
planId: "pro", // same plan they're on
successUrl: "/billing",
})
客户端用法
客户端 SDK 不包含 customerId,因为它会通过 identify 解析。
import { paykitClient } from "@/lib/paykit-client"
// Subscribe to a plan
await paykitClient.subscribe({
planId: "pro",
successUrl: `${window.location.origin}/billing?success=true`,
cancelUrl: `${window.location.origin}/billing`,
})
// Open Stripe Customer Portal (manage payment methods, invoices)
await paykitClient.customerPortal({
returnUrl: window.location.href,
})
读取订阅状态
const customer = await paykit.getCustomer({ id: "user_123" })
for (const sub of customer.subscriptions) {
console.log(sub.planId) // "pro"
console.log(sub.status) // "active", "canceled", etc.
console.log(sub.cancelAtPeriodEnd) // true if pending cancellation
console.log(sub.currentPeriodEnd) // when the current period ends
}
处理结账重定向
当 subscribe() 返回 paymentUrl 时,将用户重定向到该地址以完成支付:
服务端组件 / API 路由:
import { redirect } from "next/navigation"
const { paymentUrl } = await paykit.subscribe({
customerId: userId,
planId: "pro",
successUrl: `${process.env.NEXT_PUBLIC_APP_URL}/billing?success=true`,
})
if (paymentUrl) {
redirect(paymentUrl)
}
客户端:
const result = await paykitClient.subscribe({
planId: "pro",
successUrl: `${window.location.origin}/billing?success=true`,
})
返回 paymentUrl 时,客户端 SDK 会自动处理重定向。
Webhook
Stripe 会针对订阅生命周期事件发送 Webhook。PayKit 会通过路由处理程序自动处理这些事件。
确保在 Stripe 中将 Webhook 端点配置为 {your-domain}/paykit/api/webhook。
如需在应用中响应订阅变更:
export const paykit = createPayKit({
// ...
on: {
"customer.updated": ({ payload }) => {
// Sync subscription state to your app
await updateUserRole(payload.customerId, payload.subscriptions)
},
},
})
Stripe 客户门户
让客户管理其账单(更新支付方式、查看发票、取消订阅):
// Server-side
const { url } = await paykit.customerPortal({
customerId: "user_123",
returnUrl: "https://example.com/billing",
})
// Client-side
await paykitClient.customerPortal({
returnUrl: window.location.href,
})
评论
支持 Markdown