ZPAY 支付接入
用 ZPAY / 易支付完成一次性付款、会员售卖和数字商品自动发货。
快速版
ZPAY 适合先跑通国内一次性付款:用户在 01MVP 页面下单,跳转到 ZPAY 收银台,付款成功后 ZPAY 回调 /api/payments/webhook/zpay,系统再更新订单、记录购买、发放积分或发送数字商品邮件。
ZPAY 官网是 https://z-pay.cn/。 国内资料里有时会写成 7pay,它和 ZPAY 指的是同一个品牌。
这一版做了两条路径:
| 路径 | 用途 | 渠道配置 |
|---|---|---|
| 会员 / 账单页 | 支持 01mvp_full、01mvp_pro 这类 299 / 699 一次性会员售卖 | 开启 zpay:alipay 或 zpay:wxpay |
| 数字商品页 | /digital-products 售卖文字内容、链接、兑换码 | 开启支持数字商品的 ZPAY 渠道 |
最小配置:
PAYMENT_ENABLED_CHANNELS=zpay:alipay,zpay:wxpay
ZPAY_PID=
ZPAY_KEY=
ZPAY_DEFAULT_TYPE=alipay
NEXT_PUBLIC_ZPAY_PRODUCT_01MVP_FULL=01mvp_full
NEXT_PUBLIC_ZPAY_PRODUCT_01MVP_PRO=01mvp_pro如果还配置了 Stripe 或 Waffo,也可以在后台 /admin/payments 控制哪个渠道对用户开放。
接下来你可以:
- 在 ZPAY 商户后台拿到商户 ID 和密钥
- 配置
ZPAY_PID、ZPAY_KEY、PAYMENT_ENABLED_CHANNELS和线上站点 URL - 在
/admin/payments确认 ZPAY 渠道已启用 - 在后台
/admin/digital-products新增一个 draft 商品 - 填好价格、交付内容或兑换码后切到 active
- 用测试账号在
/digital-products下单,确认支付回调和邮件发货
费用与限制
ZPAY 的手续费由两部分组成:
| 项目 | 费率 |
|---|---|
| ZPAY 平台费 | 1.0% |
| 支付宝/微信通道费 | 0.6% |
| 合计 | 1.6% |
对比直接对接微信/支付宝官方商户,标准费率仅 0.6%,ZPAY 每笔多付 1% 的平台抽成。
小额低频时感觉不明显,但如果月流水 10 万,一年差下来就是 (1.6% - 0.6%) × 10 万 × 12 = 12,000 元。
另外,个人身份(小微商户)有收款限制:
- 单笔限额 1,000 元
- 单日限额 10,000 元
- 提交资料需与本账号实名信息一致,否则审核失败
什么时候用 ZPAY
适合:早期 MVP 快速验证,个人无执照,日流水 1 万以内——ZPAY 开通简单、接入快,是最省事的起步方案。
不适合:项目跑起来后日流水稳定超过 1 万,或者想省掉那 1% 的平台费。这时候建议换成微信/支付宝官方商户(标准费率 0.6%,无限额,对公结算),虽然开通和接入麻烦一点,但长期更划算。
接入结构
支付通道代码放在 packages/payment,业务代码放在 apps/01mvp-web/src/lib/digital-products。
这样做是为了以后能换通道:
- ZPAY Provider 只负责签名、下单、查单、退款和回调验签。
- 数字商品服务负责商品、订单、交付内容、兑换码库存和邮件。
- 会员购买仍然走统一的
PaymentProvider接口,由支付渠道决定实际使用 Stripe、Waffo 还是 ZPAY。 - 数字商品页从
checkoutChannels读取可用支付方式。当前 ZPAY 的支付宝和微信支付可以直接用于数字商品,其他 provider 需要补齐对应的一次性付款能力后再加入。
环境变量
# 启用的支付渠道。留空时会启用所有密钥完整的渠道。
PAYMENT_ENABLED_CHANNELS=zpay:alipay,zpay:wxpay
# ZPAY 商户配置
ZPAY_PID=
ZPAY_KEY=
ZPAY_DEFAULT_TYPE=alipay # alipay | wxpay
# 默认网关。通常不需要改,除非商户后台给了独立网关。
ZPAY_SUBMIT_URL=https://zpayz.cn/submit.php
ZPAY_API_URL=https://zpayz.cn/api.php
# 会员页 299 / 699 的本地商品标识
NEXT_PUBLIC_ZPAY_PRODUCT_01MVP_FULL=01mvp_full
NEXT_PUBLIC_ZPAY_PRODUCT_01MVP_PRO=01mvp_pro线上还要确保站点 URL 正确:
NEXT_PUBLIC_SITE_URL=https://your-domain.com回调地址:
https://your-domain.com/api/payments/webhook/zpay数字商品
后台地址:
/admin/digital-products支持两种交付方式:
| 交付方式 | 适合 |
|---|---|
| 固定文字内容 | 一段自由文本,可以写下载链接、使用说明、资料入口、社群链接 |
| 一单一个兑换码 | License、优惠码、一次性兑换码 |
用户付款成功后,系统会把内容发送到注册邮箱。订单页也会显示已交付内容,并提供复制按钮,避免邮件延迟时用户完全看不到结果。
数字商品订单不会直接塞进支付包。支付包只做通道能力,商品、库存、发货、售后留在应用层。
退款
后台最近订单里可以触发退款。为了避免误点,需要输入 REFUND 才会提交。
退款成功后会做三件事:
- 把数字商品订单改成
refunded。 - 同步把对应
Purchase记录改成refunded。 - 写入后台审计日志。
数字商品退款后的内容无法真正收回,所以商品页面和售后规则仍然要写清楚适用范围。
同时开启多个支付
可以同时开启。
推荐的第一版组合:
| 页面 | 推荐通道 |
|---|---|
/pricing 会员页 | 从已启用的账单渠道中选择,如 Stripe、Waffo 或 ZPAY |
/digital-products 数字商品页 | 从统一渠道注册表读取;当前 ZPAY 可直接使用 |
| 后续海外数字商品页 | 可以加 Stripe Checkout |
| 后续国内正式订阅 | 建议接微信支付或支付宝官方通道 |
不要把数字商品支付按钮直接写死在页面里。应该在应用层维护 checkoutChannels,再把订单交给对应 Provider 创建支付链接。
测试
本地至少测这些:
pnpm --filter @01mvp/payment test -- zpay
pnpm --filter 01mvp-web test
pnpm --filter 01mvp-web type-check没有真实 key 时,可以先测:
- ZPAY 签名生成和回调验签
- 数字商品建表和 Drizzle migration
- 后台商品创建表单是否能通过类型检查
- 回调分流是否会根据
param.kind进入数字商品或会员路径
拿到真实 key 后,再测一单小额真实支付:
- 新增一个 1 元以内的测试商品。
- 购买后确认 ZPAY 后台有订单。
- 确认本地订单从
pending变成fulfilled。 - 确认注册邮箱收到交付内容。
- 对测试订单执行退款,确认后台订单变成
refunded。