Stripe 支付接入指南

Stripe 支付接入指南

路由说明

启用条件:PULSE_STRIPE_SECRET_KEY 非空 PULSE_SHOP_ENABLED=true

方法 路径 说明
POST /webhook/stripe Stripe Webhook 回调
GET /shop/plans 套餐列表(JSON API)
POST /shop/checkout 创建 Stripe Checkout Session
GET /panel/shop 商店页面(用户侧)
GET /panel/shop/success 支付成功页
GET /panel/plans 管理员套餐 CRUD

环境变量

PULSE_STRIPE_SECRET_KEY=sk_test_...     # Stripe Secret Key(必填)
PULSE_SHOP_ENABLED=true                  # 显式开启商店(必填)
PULSE_STRIPE_WEBHOOK_SECRET=whsec_...   # Webhook 签名密钥(生产环境必填)

PULSE_STRIPE_WEBHOOK_SECRET 留空时不验签,生产环境务必配置

传入方式

项目不读 .env 文件,需手动传入:

# 方式一:命令前加变量
PULSE_STRIPE_SECRET_KEY=sk_test_xxx PULSE_SHOP_ENABLED=true make dev

# 方式二:export 到当前 shell(同一窗口运行 make dev)
export PULSE_STRIPE_SECRET_KEY=sk_test_xxx
export PULSE_SHOP_ENABLED=true
make dev

# 方式三:direnv(推荐,写 .env 文件后 direnv allow)

Stripe Dashboard 配置

1. 获取 Secret Key

dashboard.stripe.com/apikeys → 复制 Secret keysk_test_...

2. 配置 Webhook

dashboard.stripe.com/webhooks → Add endpoint:

  • URL:https://你的域名/webhook/stripe
  • 事件:至少勾选 checkout.session.completed
  • 创建后点进去 → Signing secret → Reveal → 复制 whsec_...

3. 创建 Product & Price

  1. Products → Add product
  2. 填写名称,添加价格(选择一次性或订阅)
  3. 创建后进入 Product 详情页 → Pricing 部分 → 复制 price_xxx

:warning: 注意:prod_xxx 是 Product ID,price_xxx 才是 Price ID,填错会报 resource_missing


测试模式

Stripe Dashboard 右上角开启 Sandbox(旧版叫 Test mode),此模式下:

  • API Key 为 sk_test_... 开头
  • 支付不会真实扣款

测试卡号:

字段
卡号 4242 4242 4242 4242
有效期 任意未来日期(如 12/34
CVC 任意 3 位(如 123

套餐配置注意事项

套餐类型必须与 Stripe Price 类型匹配,否则报错:

Pulse 套餐类型 Stripe Price 类型
one_time One-time(一次性)
subscription Recurring(订阅)

错误示例:套餐类型为 one_time 但 Stripe Price 是订阅价格,会报:

You specified `payment` mode but passed a recurring price.

本地 Webhook 测试

方式一:ngrok(无需安装 Stripe CLI)

brew install ngrok
ngrok http 8080
# 将 ngrok URL 填入 Stripe Dashboard Webhook endpoint

方式二:Stripe CLI

brew install stripe/stripe-cli/stripe
stripe login
stripe listen --forward-to localhost:8080/webhook/stripe
# 终端会打印临时 whsec_...,用作 PULSE_STRIPE_WEBHOOK_SECRET

常见错误排查

错误 原因 解决
plan has no Stripe price configured 套餐未填 Stripe Price ID 编辑套餐填入 price_xxx
No such price: 'prod_xxx' 填了 Product ID 而非 Price ID 在 Product 详情 Pricing 部分复制 price_xxx
payment mode but passed a recurring price 套餐类型与 Price 类型不匹配 统一为 subscriptionone_time
CSRF token invalid HTMX 请求未携带 CSRF token 确认 shared.htmldocument.addEventListener 而非 document.body.addEventListener
failed to create checkout session Stripe API 调用失败 查看服务端日志具体错误