Stripe 还是 Creem

两条支付通道都已接好。真正的差别在哪,以及怎么切换。

两家支付商都已经实现。webhook 路由负责验签、去重,并把任意一家的 payload 翻译成 同一个内部的 PaymentEvent;你的功能模块只处理这个事件,从不直接引入支付商的 客户端。所以这个选择可以往后放,以后再改也不会把任何人晾在半路: PAYMENT_PROVIDER 只决定新的结账走哪一家,已有的订阅在哪里开始就在哪里续费, 依据是订阅那一行记录的 provider。

差别在哪

StripeCreem
角色支付处理方——你自己是登记商户(merchant of record)登记商户——他们卖,你收钱
销售税与增值税自己处理,或者加上 Stripe Tax由对方代收代缴
应用内变更套餐升级立即生效并补差价,降级在周期结束时生效走支付商自己的门户
升级差价被退款撤销升级——价格恢复,补发的额度收回
本地 webhook 测试bun run stripe:listen,通过 Stripe CLI/creem skill 发送一个带签名的 payload
商品目录 idstripePriceId,每个档位、每种周期各一个creemProductId,每个档位、每种周期各一个
开关PAYMENT_PROVIDER=stripePAYMENT_PROVIDER=creem

唯一值得提前规划的不对称之处是套餐变更。应用内的升级和降级只支持 Stripe (src/features/billing/plan-change.ts);Creem 的订阅用户想换档位,要去 Creem 的门户。其余的一切——结账、续费、退款、取消,以及挂在每个事件上的积分发放—— 在两家上的行为完全一致。

切换

PAYMENT_PROVIDER 在启动时读取,所以在 .dev.vars(本地)和 .prod.vars (生产)里设置后重启。如果没有设置,模板会退回到已配置了密钥的那一家,优先 Stripe。

在当前支付商的密钥配好之前,什么都买不了;每个购买按钮读的都是这个状态,而不是 弹出一个注定失败的结账页——产品总是比支付通道先上线,而商户账号的审核要几周。

运行 /stripe/creem skill 来创建商品目录、把 id 写进 src/config/plans.ts,并在信任它之前把 webhook 端到端验证一遍。