MaPay 码支付 — 对接文档

版本 v1.0  |  更新日期:2026-08-10  |  接口地址:https://test1.pay.sckeji.top

目录

  1. 系统概述与架构
  2. 商户接入准备
  3. 创建订单 API
  4. 签名算法
  5. 异步回调通知
  6. 同步跳转
  7. 查询订单状态
  8. 监控端对接
  9. 错误码一览
  10. 常见问题
  11. 对接检查清单

一、系统概述

MaPay 是一套基于个人微信/支付宝收款码的免签约支付系统。商户无需申请官方支付接口,通过"个人收款码 + PC监控端"即可实现在线收款的自动回调。

系统架构

┌─────────────┐ ①创建订单 ┌──────────────────────┐ │ 商户网站 │ ──────────────────▶ │ MaPay 码支付系统 │ │ (第三方对接) │ ◀────────────────── │ test1.pay.sckeji.top │ └─────────────┘ ⑤异步回调通知 └──────────┬───────────┘ ▲ │ │ ②返回收银台URL │ ▼ │ ┌──────────────────┐ │ │ 收银台页面 │ │ │ /Pay/console/ │ │ └──────────────────┘ │ │ │ ③用户扫码付款 │ │ ▼ │ ┌──────────────────────────┐ │ │ PC 监控端 (Windows) │ │ │ 监听手机收款到账通知 │ │ └──────────┬───────────────┘ │ │ ④上报收款金额 │ ▼ │ ┌──────────────────────────┐ └──────────────────── │ 监控匹配模块 │ 返回 "success" │ 金额匹配 → 触发回调 │ └──────────────────────────┘

完整支付流程

  1. 商户网站 调用 MaPay 创建订单 API,获取收银台链接和二维码
  2. 用户 打开收银台页面,用微信/支付宝扫码支付
  3. PC监控端 实时监听手机上的收款通知,解析到账金额
  4. 监控模块 将金额与系统中的待支付订单进行匹配
  5. 匹配成功 后,系统自动向商户网站发送异步回调通知
  6. 商户网站 验证签名后确认订单完成,返回 success

二、商户接入准备

2.1 获取商户凭证

凭证说明
pid商户ID,唯一数字标识
secret_key商户密钥,用于签名验证,请妥善保管

2.2 接口规范

项目说明
接口地址https://test1.pay.sckeji.top
请求方式POST(部分接口支持 GET)
数据格式application/x-www-form-urlencoded
字符编码UTF-8
签名算法MD5

三、创建订单

3.1 页面跳转方式 GET/POST

适用于表单提交跳转收银台的场景。

接口地址:https://test1.pay.sckeji.top/submit

3.2 API方式(推荐)POST

适用于前后端分离或移动端场景,返回 JSON 数据。

接口地址:https://test1.pay.sckeji.top/mapi

请求参数(通用)

参数类型必填说明
pidint必填商户ID
typestring必填支付方式:wxpay=微信,alipay=支付宝
out_trade_nostring必填商户订单号(需唯一)
notify_urlstring必填异步通知地址(支付结果回调URL)
return_urlstring可选同步跳转地址(支付成功后浏览器跳转)
namestring必填商品名称
moneyfloat必填订单金额(元,如 10.00)
signstring必填MD5签名
sign_typestring必填固定值 MD5

API方式响应示例

成功:
{
    "code": 1,
    "msg": "订单创建成功",
    "trade_no": "H2026081012345678",
    "qrcode": "https://test1.pay.sckeji.top/Pay/console/H2026081012345678"
}
失败:{"code": 0, "msg": "签名错误"}
字段说明
code1=成功,其他=失败
trade_no平台订单号
qrcode收银台地址(可生成二维码供用户扫描)

四、签名算法

签名步骤

  1. 将所有请求参数(不含 sign 和 sign_type)按参数名字典序排列
  2. 将排序后的参数用 & 连接,格式 key=value,空值参数不参与
  3. 在拼接字符串末尾追加商户密钥 secret_key
  4. 对拼接结果做 MD5 运算(32位小写)

签名示例

假设参数:pid=1001, type=wxpay, out_trade_no=ORDER_001, name=测试商品, money=10.00, notify_url=https://your-site.com/notify

排序拼接:

money=10.00&name=测试商品¬ify_url=https://your-site.com/notify&out_trade_no=ORDER_001&pid=1001&type=wxpay

追加密钥后 MD5:

sign = md5("money=10.00&name=测试商品&...&type=wxpay" + "你的secret_key")

PHP 签名代码

function createSign(array $params, string $secret_key): string
{
    unset($params['sign'], $params['sign_type']);
    $params = array_filter($params, fn($v) => $v !== '');
    ksort($params);
    $signStr = '';
    foreach ($params as $k => $v) {
        $signStr .= $k . '=' . $v . '&';
    }
    $signStr = substr($signStr, 0, -1) . $secret_key;
    return md5($signStr);
}

Python 签名代码

import hashlib

def create_sign(params: dict, secret_key: str) -> str:
    filtered = {k: v for k, v in params.items()
                if k not in ('sign', 'sign_type') and v != ''}
    sign_str = '&'.join(f'{k}={filtered[k]}' for k in sorted(filtered))
    sign_str += secret_key
    return hashlib.md5(sign_str.encode('utf-8')).hexdigest()

Java 签名代码

public static String createSign(Map<String, String> params, String secretKey) {
    TreeMap<String, String> sorted = new TreeMap<>();
    for (var e : params.entrySet()) {
        if (!"sign".equals(e.getKey()) && !"sign_type".equals(e.getKey())
            && !e.getValue().isEmpty()) {
            sorted.put(e.getKey(), e.getValue());
        }
    }
    StringBuilder sb = new StringBuilder();
    for (var e : sorted.entrySet()) {
        sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
    }
    sb.deleteCharAt(sb.length() - 1).append(secretKey);
    return DigestUtils.md5Hex(sb.toString());
}

五、异步回调通知(核心)

支付成功后,系统会向商户的 notify_url 发送异步通知。

5.1 通知参数

系统通过 GET 方式将参数附加到 notify_url:

参数类型说明
pidint商户ID
trade_nostring平台订单号
out_trade_nostring商户订单号
typestring支付方式:wxpay / alipay
namestring商品名称
moneystring订单金额(元)
trade_statusstringTRADE_SUCCESS = 交易成功
sign_typestringMD5
signstringMD5签名

5.2 通知示例

GET https://your-site.com/notify?pid=1001&trade_no=H2026081012345678
    &out_trade_no=ORDER_001&type=wxpay&name=测试商品
    &money=10.00&trade_status=TRADE_SUCCESS
    &sign_type=MD5&sign=abc123...

5.3 商户处理流程

收到通知 → 验证签名 → 检查 trade_status → 校验金额 → 处理业务 → 返回 "success"
关键注意事项:
  • 必须验证签名:防止伪造通知攻击
  • 必须校验金额:核对 money 与订单金额是否一致
  • 必须做幂等处理:同一订单可能收到多次通知
  • 必须返回纯文本 success:否则系统认为通知失败

5.4 重试策略

次数间隔
第1次支付成功后立即通知
第2次5秒后重试
第3次30秒后重试
第4次5分钟后重试

5.5 PHP 验签示例

// 接收通知
$data = $_GET;
$sign = $data['sign'];
unset($data['sign']);

// 验签
$mySign = createSign($data, $my_secret_key);
if ($mySign !== $sign) {
    exit('签名验证失败');
}

// 处理业务
if ($data['trade_status'] === 'TRADE_SUCCESS') {
    $order = findOrder($data['out_trade_no']);
    if ($order && $order['money'] == $data['money'] && $order['status'] == 0) {
        updateOrderPaid($order['id']);
        echo 'success';  // 必须返回 success
    }
}

5.6 Python 验签示例(Flask)

@app.route('/notify')
def payment_notify():
    data = request.args.to_dict()
    sign = data.pop('sign', '')
    # 验签
    filtered = {k: v for k, v in data.items() if v != ''}
    sign_str = '&'.join(f'{k}={filtered[k]}' for k in sorted(filtered))
    if hashlib.md5((sign_str + SECRET_KEY).encode()).hexdigest() != sign:
        return '签名失败', 403
    # 处理业务
    if data.get('trade_status') == 'TRADE_SUCCESS':
        # TODO: 校验订单、更新状态
        return 'success'

六、同步跳转

支付成功后,若创建订单时传入了 return_url,用户浏览器会跳转到该地址。

跳转参数与异步通知相同(GET方式附加在URL后)。

注意:同步跳转仅用于用户体验,不可作为支付成功的依据。请务必以异步通知为准。

七、查询订单状态

商户可主动查询订单支付状态。

接口地址:GET https://test1.pay.sckeji.top/getOrderState/{order_id}

响应示例(未支付)

{
    "order_id": "H2026081012345678",
    "passtime": 120,
    "state": 0
}

响应示例(已支付)

{
    "order_id": "H2026081012345678",
    "passtime": 0,
    "state": 1,
    "return_url": "https://your-site.com/return?pid=1001&trade_no=H20260810..."
}
字段说明
state0=待支付,1=已支付
passtime剩余有效时间(秒)

八、监控端对接

本节面向 PC 监控端开发者,说明监控端如何与系统对接。

8.1 心跳接口 POST

接口地址:https://test1.pay.sckeji.top/monitor/api/heartbeat

监控端应每 60秒 发送一次心跳。超过5分钟无心跳将标记为离线。

参数必填说明
client_id必填客户端ID
client_secret必填客户端密钥
// 响应示例
{
    "code": 1,
    "msg": "ok",
    "data": {
        "client_id": 1,
        "client_name": "我的电脑",
        "pid": 1001,
        "pay_api_url": "https://test1.pay.sckeji.top",
        "pay_secret_key": "abc123..."
    }
}

8.2 上报收款通知 POST

接口地址:https://test1.pay.sckeji.top/monitor/api/notify

参数必填说明
client_id必填客户端ID
client_secret必填客户端密钥
amount必填收款金额(元),如 10.00
pay_type可选wxpay / alipay
source可选来源标识,默认 notification
// 响应示例
{
    "code": 1,
    "msg": "回调成功",
    "data": { "matched": true }
}

8.3 金额匹配规则

系统采用"精确金额 + 递增偏移"机制:

九、错误码一览

错误信息原因解决方案
签名错误sign 验证不通过检查签名算法和密钥
用户禁用或不存在商户被禁用联系管理员
订单提交重复out_trade_no 已存在确保订单号唯一
创建订单失败无可用收款通道联系管理员配置
参数错误缺少必填参数检查参数完整性
客户端验证失败client_id/secret 错误检查监控端凭证
参数缺失或金额无效金额为0或缺失检查 amount 参数

十、常见问题

Q:订单有效期是多久?

A:订单创建后 180 秒(3分钟)内有效,超时自动关闭。

Q:支持哪些支付方式?

A:目前支持微信支付(wxpay)和支付宝(alipay)。

Q:异步通知失败了怎么办?

A:系统会自动重试多次。商户也可通过 /getOrderState/{order_id} 主动查询。

Q:如何测试对接?

A:先用小额(如 0.01 元)测试,确认签名和回调正常后再投入使用。

Q:同一金额多笔订单怎么处理?

A:系统自动递增 0.01 元区分,监控端上报实际到账金额即可。

Q:trade_no 和 out_trade_no 有什么区别?

A:trade_no 是平台订单号,out_trade_no 是商户传入的商户订单号。

十一、对接检查清单