7Pay 是一个聚合支付平台,支持支付宝和微信支付。本文记录 API 接口支付的接入方式,即在页面上展示二维码让用户扫码支付,而非跳转到第三方页面。
核心接口一览
| 接口 | 地址 | 用途 |
|---|---|---|
| API 支付 | https://zpayz.cn/mapi.php | 创建订单,获取二维码 |
| 订单查询 | https://zpayz.cn/api.php?act=order | 轮询支付状态 |
| 退款 | https://zpayz.cn/api.php?act=refund | 订单退款 |
| 余额查询 | https://zpayz.cn/api.php?act=balance | 查询账户余额 |
创建支付订单
POST https://zpayz.cn/mapi.php (form-data)
请求参数
| 参数 | 必填 | 说明 |
|---|---|---|
| pid | 是 | 商户 ID |
| type | 是 | 支付方式:alipay / wxpay |
| out_trade_no | 是 | 商户订单号(不超过 32 位,不可重复) |
| notify_url | 是 | 异步回调地址 |
| name | 是 | 商品名称(不超过 127 字节) |
| money | 是 | 金额,最多两位小数 |
| clientip | 是 | 用户 IP |
| sign | 是 | 签名(见下文) |
| sign_type | 是 | 固定 MD5 |
| device | 否 | 设备类型,默认 pc |
| param | 否 | 扩展参数,回调时原样返回 |
成功返回
json
12345678
{
"code": 1,
"msg": "成功",
"trade_no": "202601011234567890",
"qrcode": "https://xxx.cn/pay/wxpay/xxx/",
"img": "https://zpayz.cn/qrcode/123.jpg",
"payurl": "https://xxx.cn/pay/wxpay/xxx/"
}- qrcode: 用这个 URL 生成二维码图片
- img: 平台已生成的二维码图片地址,可直接使用
- payurl: 跳转支付链接(H5 场景用)
前端展示二维码
tsx
123456789
// React 示例
function PaymentQRCode({ imgUrl }: { imgUrl: string }) {
return (
<div className="payment-qrcode">
<img src={imgUrl} alt="扫码支付" />
<p>请使用支付宝/微信扫码支付</p>
</div>
);
}轮询订单状态
用户扫码后,前端需要轮询查询订单状态。
GET https://zpayz.cn/api.php?act=order&pid={商户ID}&key={商户密钥}&out_trade_no={订单号}
返回参数
| 参数 | 说明 |
|---|---|
| code | 1 成功,其他失败 |
| status | 0 未支付,1 已支付 |
| trade_no | 平台订单号 |
| money | 实际支付金额 |
| endtime | 支付完成时间 |
轮询实现
typescript
12345678910111213141516171819
async function pollPaymentStatus(
orderId: string,
maxAttempts = 60,
interval = 3000
): Promise<boolean> {
for (let i = 0; i < maxAttempts; i++) {
const res = await fetch(
`https://zpayz.cn/api.php?act=order&pid=${PID}&key=${KEY}&out_trade_no=${orderId}`
);
const data = await res.json();
if (data.code === 1 && data.status === 1) {
return true; // 支付成功
}
await new Promise(r => setTimeout(r, interval));
}
return false; // 超时
}建议轮询间隔 3 秒,最多轮询 3 分钟。
支付回调
支付完成后,平台会向 notify_url 发送 GET 请求。
回调参数
| 参数 | 说明 |
|---|---|
| pid | 商户 ID |
| trade_no | 平台订单号 |
| out_trade_no | 商户订单号 |
| type | 支付方式 |
| name | 商品名称 |
| money | 订单金额 |
| trade_status | TRADE_SUCCESS 表示成功 |
| param | 扩展参数 |
| sign | 签名 |
| sign_type | MD5 |
回调处理
typescript
123456789101112131415161718192021222324252627
// 伪代码示例
async function handlePaymentNotify(params: Record<string, string>) {
// 1. 验证签名
if (!verifySign(params)) {
return 'fail';
}
// 2. 检查订单状态
if (params.trade_status !== 'TRADE_SUCCESS') {
return 'fail';
}
// 3. 验证金额(重要!防止金额篡改)
const order = await getOrderFromDB(params.out_trade_no);
if (order.money !== params.money) {
return 'fail';
}
// 4. 处理业务逻辑(注意幂等性)
if (order.status !== 'paid') {
await updateOrderStatus(params.out_trade_no, 'paid');
// 其他业务逻辑...
}
// 5. 返回 success 告知平台已收到
return 'success';
}回调重试策略
如果你的服务器没有返回 success,平台会按以下间隔重试:
0s → 15s → 15s → 30s → 180s → 1800s → 1800s → 1800s → 1800s → 3600s
签名算法
MD5 签名步骤:
- 筛选参数:排除
sign、sign_type和空值 - 按 ASCII 码排序参数名
- 拼接成
a=b&c=d格式(不要 URL 编码) - 末尾拼接商户密钥:
a=b&c=d&e=f{KEY} - MD5 加密,结果转小写
typescript
123456789101112131415161718192021
import { createHash } from 'crypto';
function generateSign(params: Record<string, string>, key: string): string {
// 过滤并排序
const sorted = Object.keys(params)
.filter(k => k !== 'sign' && k !== 'sign_type' && params[k] !== '')
.sort()
.map(k => `${k}=${params[k]}`)
.join('&');
// 拼接密钥并 MD5
return createHash('md5')
.update(sorted + key)
.digest('hex');
}
function verifySign(params: Record<string, string>, key: string): boolean {
const sign = params.sign;
const calculated = generateSign(params, key);
return sign === calculated;
}订单退款
POST https://zpayz.cn/api.php?act=refund
请求参数
| 参数 | 必填 | 说明 |
|---|---|---|
| pid | 是 | 商户 ID |
| key | 是 | 商户密钥 |
| trade_no | 二选一 | 平台订单号 |
| out_trade_no | 二选一 | 商户订单号 |
| money | 是 | 退款金额(通常需与原订单一致) |
返回示例
json
1234
{
"code": 1,
"msg": "退款成功"
}安全注意事项
- 验证签名:回调必须验签,防止伪造通知
- 验证金额:回调金额与数据库订单金额对比,防止金额篡改
- 幂等处理:同一订单可能收到多次回调,避免重复处理
- 密钥保护:商户密钥只能放在服务端,不能暴露给前端
- HTTPS:notify_url 建议使用 HTTPS
- IP 白名单:生产环境可考虑验证回调来源 IP
完整流程
plaintext
123456
1. 用户下单 → 前端调用后端创建订单接口
2. 后端调用 mapi.php → 获取 qrcode/img
3. 前端展示二维码 → 开始轮询订单状态
4. 用户扫码支付 → 平台回调 notify_url
5. 后端验签处理 → 返回 success
6. 前端轮询发现已支付 → 跳转成功页