Stripe 接入
配置 Stripe Checkout、价格、Webhook、订阅,并在测试环境完成验收。
Stripe 是 Starter 内置的两个支付适配器之一。当前集成使用托管 Checkout、订阅到期取消、Customer Portal 和带签名的 Webhook。
1. 创建商品和价格
为 Starter 展示的每个订阅周期创建周期性价格,并为所有可见积分包创建一次性价格。复制 Stripe Price ID(price_...),不要使用 Product ID(prod_...)。
默认商品目录需要以下配置:
STRIPE_PRICE_STARTER_MONTHLY=price_xxx
STRIPE_PRICE_STARTER_ANNUAL=price_xxx
STRIPE_PRICE_PRO_MONTHLY=price_xxx
STRIPE_PRICE_PRO_ANNUAL=price_xxx
STRIPE_PRICE_CREDITS_SMALL=price_xxx
STRIPE_PRICE_CREDITS_MEDIUM=price_xxx
STRIPE_PRICE_CREDITS_LARGE=price_xxx旧变量 STRIPE_PRICE_STARTER 和 STRIPE_PRICE_PRO 仍可作为月付价格的后备值,但新项目应使用明确的 _MONTHLY 变量名。
Enterprise 和落地页商品的环境变量只是扩展点。Enterprise 不在内置方案目录中,示例落地页权益也没有完整的结账履约逻辑。完成并测试对应商品行为前,不要公开这些 SKU。
2. 配置 Stripe
NEXT_PUBLIC_ENABLE_PAYMENTS=true
PAYMENTS_PROVIDER=stripe
STRIPE_SECRET_KEY=sk_test_xxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_PRICE_STARTER_MONTHLY=price_xxx
STRIPE_PRICE_STARTER_ANNUAL=price_xxx
STRIPE_PRICE_PRO_MONTHLY=price_xxx
STRIPE_PRICE_PRO_ANNUAL=price_xxx
STRIPE_PRICE_CREDITS_SMALL=price_xxx
STRIPE_PRICE_CREDITS_MEDIUM=price_xxx
STRIPE_PRICE_CREDITS_LARGE=price_xxx
CRON_SECRET=replace_with_a_strong_random_server_secret同一环境必须整套使用同一种模式的配置:
- 测试模式 Secret Key 和 Publishable Key;
- 测试模式 Price ID;
- 测试端点或本地 Stripe CLI 生成的签名密钥。
完成生产环境验收后,再把整套配置一起切换为对应的生产模式值。绝不能把 STRIPE_SECRET_KEY、STRIPE_WEBHOOK_SECRET 或 CRON_SECRET 暴露给浏览器代码。
内置 Stripe Checkout 适配器当前明确只请求卡支付。启用可能延迟完成的支付方式前,请先接入并测试异步支付事件。
3. 配置 Webhook
创建 Stripe Webhook 端点:
https://your-domain.com/api/payments/webhook订阅以下事件:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_succeededinvoice.payment_failed
该路由会基于未经修改的原始请求体校验 Stripe-Signature。把端点签名密钥写入 STRIPE_WEBHOOK_SECRET。
本地转发可以使用:
stripe login
stripe listen --forward-to http://localhost:3000/api/payments/webhookStripe CLI 输出的签名密钥只能用于本地环境。
4. 结账与生命周期
请调用统一路由,不要调用服务商专用路由:
POST /api/payments/checkout
Content-Type: application/json
{ "skuKey": "credits_small" }POST /api/payments/subscription/checkout
Content-Type: application/json
{ "planKey": "starter", "period": "month" }结账适配器会把用户 ID 和商品目录元数据写入 Checkout Session;订阅结账还会把这些信息写入 subscription_data。订阅结账使用服务端生成的幂等键。
取消订阅会将 Stripe 订阅更新为 cancel_at_period_end: true。Customer Portal 使用订阅记录中保存的客户 ID 创建。即使以后切换了部署实例的当前支付服务商,这些操作仍会继续调用 Stripe。
成功跳转只会显示通用的成功通知,不会查询 Stripe,也不会发放积分。请等待 Webhook 完成处理,并检查持久状态。
5. 在测试模式验证
先运行静态检查和自动化测试:
npm run preflight
npm run test:unit可选的托管结账冒烟测试会创建真实的 Stripe 测试模式 Checkout Session,但不会提交付款:
PAYMENT_PROVIDER_SANDBOX_E2E=true \
E2E_TEST_EMAIL=<existing-test-user-email> \
E2E_TEST_PASSWORD=<test-user-password> \
PLAYWRIGHT_BASE_URL=https://<preview-or-test-origin> \
npm run e2e -- tests/e2e/payment-provider-sandbox.spec.ts --project=chromium本地服务应设置 PLAYWRIGHT_BASE_URL=http://localhost:3000。缺少任一测试凭证时,该测试会主动 skip,因此命令显示绿色并不足以通过验收:测试摘要必须明确显示 2 passed 和 0 skipped。
完整验收还必须包括:
- 完成一笔 Stripe 测试支付;
- 事件已投递到公网 HTTPS Webhook;
- 从数据库回读订阅或积分账本;
- 重放重复事件,确认没有重复履约;
- 验证到期取消与 Customer Portal。
请阅读 Webhook、订阅与积分,了解持久履约模型。