跳过主要内容
文档目录

Stripe

如何设置和使用 Stripe 处理支付和订阅

MinuteShip 使用 Stripe 进行支付管理,支持一次性支付和订阅支付。

设置

MinuteShip 模板默认提供三种价格计划:免费计划、专业版订阅计划(月度/年度)和终身计划(一次性支付),按照以下步骤设置:

创建 Stripe 账户

在 stripe.com 创建 Stripe 账户。

获取 API 密钥

从 Stripe 控制台获取您的 API 密钥:

  • 进入到 Stripe 控制台 > Developers > API keys
  • 复制密钥(注意:测试模式以 sk_test_ 开头,生产模式以 sk_live_ 开头)
  • 将其保存到环境变量文件中作为 STRIPE_SECRET_KEY

设置 Webhook

设置 Webhook 并获取您的 Webhook 密钥:

  • 进入到 Stripe 控制台 > Developers > Webhooks
  • 点击 Add endpoint
  • 输入 Webhook URL:https://YOUR-DOMAIN.com/api/webhooks/stripe
  • 选择要监听的事件:
    • invoice.paid
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • charge.refunded
  • 点击 Reveal 查看 Webhook 签名密钥(以 whsec_ 开头)
  • 将其保存到环境变量文件中作为 STRIPE_WEBHOOK_SECRET

创建产品和价格计划

在 Stripe 中创建产品并设置价格计划:

  • 进入到 Stripe 控制台 > Product Catalog
  • 创建专业版订阅计划的产品:
    • 点击 Add product
    • 名称:专业版计划
    • 描述:具有订阅价格的高级功能
    • 添加月度价格:
      • 点击 添加价格
      • 价格:$9.90(货币选择 USD)
      • 定期:月度
      • 保存并复制价格 ID(以 price_ 开头),这将用于 VITE_STRIPE_PRICE_PRO_MONTHLY
    • 添加年度价格:
      • 点击 Add price
      • 价格:$99.00(货币选择 USD)
      • 定期:年度
      • 保存并复制价格 ID(以 price_ 开头),这将用于 VITE_STRIPE_PRICE_PRO_YEARLY
  • 创建终身计划的产品:
    • 点击 Add product
    • 名称:终身计划
    • 描述:终身访问的一次性支付
    • 添加价格:
      • 价格:$199.00(货币选择 USD)
      • 类型:一次性
      • 保存并复制价格 ID(以 price_ 开头),这将用于 VITE_STRIPE_PRICE_LIFETIME

添加环境变量

添加以下环境变量:

.env

# 支付提供商
VITE_PAYMENT_PROVIDER=stripe

STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Price plans
VITE_STRIPE_PRICE_PRO_MONTHLY=price_...
VITE_STRIPE_PRICE_PRO_YEARLY=price_...
VITE_STRIPE_PRICE_LIFETIME=price_...

更新网站配置

更新 src/config/website.ts 中的 payment 部分,配置价格计划 — 金额、货币、周期和计划元数据。enable、provider 和 priceId 字段会根据环境变量(VITE_PAYMENT_PROVIDER 和 VITE_STRIPE_PRICE_*)自动解析,无需硬编码。

您必须配置此部分,使其与您在 Stripe 中创建的产品和价格一致:

src/config/website.ts

payment: {
  enable: isPaymentEnabled,              // ← 自动:当 VITE_PAYMENT_PROVIDER 设置时为 true
  provider: isPaymentEnabled ? paymentProvider : undefined, // ← 自动:'stripe'
  price: {
    plans: {
      free: {
        id: 'free',
        prices: [],
        isFree: true,
        isLifetime: false,
      },
      pro: {
        id: 'pro',
        prices: [
          {
            type: 'subscription',
            priceId: priceIds.proMonthly,  // ← 自动:来自 VITE_STRIPE_PRICE_PRO_MONTHLY
            amount: 990,                   // 金额,单位为分($9.90)
            currency: 'USD',
            interval: 'month',
          },
          {
            type: 'subscription',
            priceId: priceIds.proYearly,   // ← 自动:来自 VITE_STRIPE_PRICE_PRO_YEARLY
            amount: 9900,                  // 金额,单位为分($99.00)
            currency: 'USD',
            interval: 'year',
          },
        ],
        isFree: false,
        isLifetime: false,
        popular: true,
      },
      lifetime: {
        id: 'lifetime',
        prices: [
          {
            type: 'one_time',
            priceId: priceIds.lifetime,     // ← 自动:来自 VITE_STRIPE_PRICE_LIFETIME
            amount: 19900,                  // 金额,单位为分($199.00)
            currency: 'USD',
            allowPromotionCode: true,
          },
        ],
        isFree: false,
        isLifetime: true,
      },
    },
  },
},

Note

如果您正在设置环境,现在可以回到环境配置文档并继续。本文档的其余部分可以稍后阅读。


核心功能

  • 一次性支付成为终身会员功能
  • 定期订阅支付(月度/年度)
  • 支持免费试用期
  • 订阅管理与客户门户集成
  • 支付事件的 Webhook 处理
  • 订阅状态的跟踪和验证功能
  • 内置价格组件(表格、卡片、按钮)
  • 安全支付操作的服务器端操作
  • 多种价格计划支持(免费、专业版、终身制)

开发环境

对于本地开发,您可以使用 Stripe CLI 将事件转发到您的本地服务器:

按照 Stripe CLI 文档完成安装,然后登录到与 STRIPE_SECRET_KEY 相同的 Stripe 测试模式账户:

stripe login

将事件转发到您的本地服务器:

stripe listen \
  --skip-update \
  --events checkout.session.completed,customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,invoice.paid,charge.refunded \
  --forward-to http://localhost:3000/api/webhooks/stripe

CLI 会输出一个临时 Webhook 签名密钥。将它复制到 .env.local,然后重启开发服务器:

STRIPE_WEBHOOK_SECRET=whsec_...

模板还提供 Stripe 测试模式 E2E 套件:

pnpm e2e:stripe

支付确认与事件顺序

invoice.paid 是 Stripe 支付成功的权威事件。checkout.session.completed 用于创建本地支付上下文,但不会单独授予访问权限。

Stripe 不保证事件投递顺序。如果 invoice.paid 先到达,MinuteShip 会在本次请求中还原 Checkout Session 并创建已支付记录。支付结果页随后按 Checkout Session ID 和当前登录用户查找记录,不需要等待 Stripe 再次投递。

该流程也支持完全折扣的 Lifetime 结账。零金额订单没有 PaymentIntent,因此 MinuteShip 会通过生成的 Invoice 和客户信息完成匹配。

Webhook 响应与重试

结果HTTP 状态码
支付功能未启用200
Stripe 不是当前配置的支付提供商404
缺少负载或 Stripe-Signature 请求头400
签名无效400
处理成功或安全地忽略重复事件200
Stripe API 或数据库临时故障500

MinuteShip 会对临时故障返回 500,让 Stripe 重试。重复投递会以幂等方式处理。

客户门户

Stripe 客户门户提供了一个托管门户,供客户管理他们的订阅。您可以自定义外观和可用功能。

  • 进入到 Stripe 控制台 > Settings > Billing > Customer Portal
  • 自定义客户门户界面显示的内容,例如,您可以添加一个自定义的 logo 和标题
  • 点击 Save changes 保存门户配置

生产环境

  1. 进入到 Stripe 控制台 > 开发者 > Webhooks
  2. 点击 添加端点
  3. 输入 Webhook URL:https://YOUR-DOMAIN.com/api/webhooks/stripe
  4. 选择要监听的事件:
    • invoice.paid
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • charge.refunded
  5. 创建后,点击 显示 查看 Webhook 签名密钥
  6. 复制 Webhook 签名密钥(以 whsec_ 开头)并将其添加到您的环境变量中

Note

Lifetime 购买发生全额退款时,只会撤销对应订单的权限并将其标记为已取消;部分退款不会撤销权限。请保持启用 charge.refunded,否则 MinuteShip 无法收到退款状态。

测试卡

要测试 Stripe 集成,请使用 Stripe 的测试模式和测试信用卡:

  • 4242 4242 4242 4242 - 成功支付
  • 4000 0000 0000 3220 - 需要 3D 安全认证
  • 4000 0000 0000 9995 - 资金不足失败

您可以在 Stripe 文档中找到更多关于 Stripe 测试卡 的信息。

创建发票

MinuteShip 已经为一次性支付配置了发票创建功能。

src/payment/provider/stripe.ts

// Automatically create invoice for one-time payments
checkoutParams.invoice_creation = {
  enabled: true,
};

如果您想自动发送已付发票,您可以在Customer emails settings中启用它,在Email customers about下,选择Successful payments。之后,您可以在 Stripe 控制台 > 发票中访问发票。

您可以在 Stripe 文档中找到更多关于自动发送已付发票的信息。

支付流程图

这是完整的支付流程图。

Payment Diagram

常见问答

如何激活微信支付和支付宝?

您可以在 Stripe 控制台 > Settings > Payment methods 中激活微信支付和支付宝。您可以在 Stripe 文档中找到更多关于微信支付和支付宝的信息。

如何限制用户只能有一个订阅?

您可以在 Stripe 控制台 > Settings > Checkout and Payment Links > Subscriptions 中启用 Limit customers to 1 subscription,您可以在 Stripe 文档中找到更多关于限制用户只能有一个订阅的信息。

最佳实践

  1. 保护 API 密钥:永远不要在客户端代码中暴露您的 Stripe 密钥
  2. 验证 Webhook 签名:始终验证 Webhook 事件的签名
  3. 优雅处理错误:当支付失败时提供用户友好的错误消息
  4. 彻底测试 Webhooks:确保所有 Webhook 事件都得到正确处理

参考资料