ZPAY 支付接入

用 ZPAY / 易支付完成一次性付款、会员售卖和数字商品自动发货。

快速版

ZPAY 适合先跑通国内一次性付款:用户在 01MVP 页面下单,跳转到 ZPAY 收银台,付款成功后 ZPAY 回调 /api/payments/webhook/zpay,系统再更新订单、记录购买、发放积分或发送数字商品邮件。

ZPAY 官网是 https://z-pay.cn/。 国内资料里有时会写成 7pay,它和 ZPAY 指的是同一个品牌。

这一版做了两条路径:

路径用途渠道配置
会员 / 账单页支持 01mvp_full01mvp_pro 这类 299 / 699 一次性会员售卖开启 zpay:alipayzpay: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_PIDZPAY_KEYPAYMENT_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 才会提交。

退款成功后会做三件事:

  1. 把数字商品订单改成 refunded
  2. 同步把对应 Purchase 记录改成 refunded
  3. 写入后台审计日志。

数字商品退款后的内容无法真正收回,所以商品页面和售后规则仍然要写清楚适用范围。

同时开启多个支付

可以同时开启。

推荐的第一版组合:

页面推荐通道
/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. 新增一个 1 元以内的测试商品。
  2. 购买后确认 ZPAY 后台有订单。
  3. 确认本地订单从 pending 变成 fulfilled
  4. 确认注册邮箱收到交付内容。
  5. 对测试订单执行退款,确认后台订单变成 refunded

参考资料