Stripe 还是 Creem
两条支付通道都已接好。真正的差别在哪,以及怎么切换。
两家支付商都已经实现。webhook 路由负责验签、去重,并把任意一家的 payload 翻译成
同一个内部的 PaymentEvent;你的功能模块只处理这个事件,从不直接引入支付商的
客户端。所以这个选择可以往后放,以后再改也不会把任何人晾在半路:
PAYMENT_PROVIDER 只决定新的结账走哪一家,已有的订阅在哪里开始就在哪里续费,
依据是订阅那一行记录的 provider。
差别在哪
| Stripe | Creem | |
|---|---|---|
| 角色 | 支付处理方——你自己是登记商户(merchant of record) | 登记商户——他们卖,你收钱 |
| 销售税与增值税 | 自己处理,或者加上 Stripe Tax | 由对方代收代缴 |
| 应用内变更套餐 | 升级立即生效并补差价,降级在周期结束时生效 | 走支付商自己的门户 |
| 升级差价被退款 | 撤销升级——价格恢复,补发的额度收回 | — |
| 本地 webhook 测试 | bun run stripe:listen,通过 Stripe CLI | 由 /creem skill 发送一个带签名的 payload |
| 商品目录 id | stripePriceId,每个档位、每种周期各一个 | creemProductId,每个档位、每种周期各一个 |
| 开关 | PAYMENT_PROVIDER=stripe | PAYMENT_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 端到端验证一遍。
ShipKit