V1 MD5 开放接口
兼容易支付协议,适合已有 MD5 签名程序快速接入。
接入说明
开始联调前请先确认接口地址、商户凭证和支付配置。
请在用户中心「API 信息」获取商户 ID 与 MD5 密钥,并至少启用一个可用的支付配置。生产环境必须使用 HTTPS 通知地址。
接口能力
| 接口 | 请求方式 | 地址 | 用途 |
|---|---|---|---|
| 页面跳转支付 | GET / POST | /submit.php | 浏览器跳转到统一支付页面 |
| API 下单 | POST | /mapi.php | 服务端创建订单并返回支付链接或二维码 |
| 订单查询 | GET | /api.php?act=order | 根据平台订单号或商户订单号查询 |
| 订单退款 | POST | /api.php?act=refund | 通过 MD5 签名发起原路退款 |
| 退款查询 | POST | /api.php?act=refundquery | 查询退款处理状态 |
支付方式与场景
支付配置决定实际调用的支付通道,API 参数只选择支付方式和场景。
| 参数组合 | 支付场景 | 返回形式 | 说明 |
|---|---|---|---|
| type=alipay, scene=web | 支付宝网页/扫码 | jump 或 qrcode | 电脑端通常展示二维码,手机端可拉起支付宝 |
| type=wxpay, scene=web | 微信网页支付 | jump | 进入统一支付页后按微信环境完成授权支付 |
| type=alipay, scene=miniapp | 支付宝小程序 | jump | 拉起支付配置绑定的支付宝小程序 |
| type=wxpay, scene=miniapp | 微信小程序 | jump | 拉起支付配置绑定的微信小程序 |
channel_id 可指定已启用的支付配置。不传时系统根据支付方式、金额限制和通道路由规则自动选择。
MD5 签名规则
请求签名用于确认参数完整性和商户身份。
生成步骤
- 1
移除 sign、sign_type、数组参数和所有空值参数。
- 2
按参数名 ASCII 升序排列,并拼接为 key=value&key=value。
- 3
在待签名字符串末尾直接追加 MD5 密钥,不增加额外分隔符。
- 4
计算 MD5 并转换为 32 位小写字符串。
money=1.00&name=测试商品¬ify_url=https://merchant.example.com/pay/notify&out_trade_no=M202607150001&pid=1001&type=alipaymd5(money=1.00&name=测试商品¬ify_url=https://merchant.example.com/pay/notify&out_trade_no=M202607150001&pid=1001&type=alipay + demo_md5_key) = 1fa74af039bcfafcfff1d82292af08f0ksort($params);
$pairs = [];
foreach ($params as $key => $value) {
if (in_array($key, ['sign', 'sign_type'], true) || $value === '' || is_array($value)) continue;
$pairs[] = $key . '=' . $value;
}
$sign = strtolower(md5(implode('&', $pairs) . $md5Key));const crypto = require('crypto');
const content = Object.keys(params).sort()
.filter(k => !['sign', 'sign_type'].includes(k) && params[k] !== '')
.map(k => `${k}=${params[k]}`).join('&');
const sign = crypto.createHash('md5').update(content + md5Key).digest('hex');MD5 密钥只能保存在服务端,禁止写入网页 JavaScript、小程序或移动端安装包。
页面跳转支付
浏览器提交后直接跳转至统一支付页面,推荐使用 POST 表单。
请求参数
| 参数 | 名称 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
pid | 商户 ID | String | 是 | 用户中心 API 信息中的商户 ID | 1001 |
type | 支付方式 | String | 是 | wxpay 或 alipay | alipay |
out_trade_no | 商户订单号 | String | 是 | 同一商户下唯一,最长 100 字符 | M202607150001 |
name | 商品名称 | String | 是 | 具体商品或服务名称,最长 120 字符 | 测试商品 |
money | 订单金额 | String | 是 | 单位元,大于 0,最多两位小数 | 1.00 |
notify_url | 异步通知地址 | String | 推荐 | 支付成功后平台发起 GET 通知 | https://merchant.example.com/pay/notify |
return_url | 页面跳转地址 | String | 否 | 用户完成支付后的浏览器跳转地址 | https://merchant.example.com/pay/return |
method | 接口模式 | String | 否 | web 或 jump,默认 web | web |
scene | 支付场景 | String | 否 | web 或 miniapp,默认 web | web |
channel_id | 支付配置 ID | Integer | 否 | 指定已启用的支付配置,不传则自动路由 | 12 |
clientip | 用户 IP | String | 否 | 发起支付的真实客户端 IP | 203.0.113.10 |
buyer_id | 买家标识 | String | 否 | JSAPI 或小程序支付需要时传入 | openid_or_buyer_id |
param | 扩展参数 | String | 否 | 通知时原样返回,最长 500 字符 | order_source=shop |
sign_type | 签名类型 | String | 是 | 固定为 MD5 | MD5 |
sign | 请求签名 | String | 是 | 32 位小写 MD5 | 202cb962ac59075b964b07152d234b70 |
curl -X POST 'https://czf.xxoi.cn/submit.php' \
-d 'pid=1001' \
-d 'type=alipay' \
-d 'out_trade_no=M202607150001' \
-d 'name=测试商品' \
-d 'money=1.00' \
-d 'notify_url=https://merchant.example.com/pay/notify' \
-d 'sign_type=MD5' \
-d 'sign=<MD5_SIGN>'<form method="post" action="https://czf.xxoi.cn/submit.php">
<input type="hidden" name="pid" value="1001">
<input type="hidden" name="type" value="alipay">
<input type="hidden" name="out_trade_no" value="M202607150001">
<input type="hidden" name="name" value="测试商品">
<input type="hidden" name="money" value="1.00">
<input type="hidden" name="sign_type" value="MD5">
<input type="hidden" name="sign" value="<MD5_SIGN>">
<button type="submit">立即支付</button>
</form>请求成功后返回 HTTP 302,并跳转到统一支付页面。
{
"code": -1,
"msg": "签名校验失败"
}- out_trade_no 在同一商户下必须唯一;重复请求会返回原订单,不能更换支付场景或支付配置。
- 商品金额使用元,必须大于 0,最多保留两位小数。
- method=jump 固定返回统一支付页;method=web 根据支付方式返回支付链接或二维码。
API 下单
服务端创建支付订单,返回支付链接或二维码信息。
请求参数
| 参数 | 名称 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
pid | 商户 ID | String | 是 | 用户中心 API 信息中的商户 ID | 1001 |
type | 支付方式 | String | 是 | wxpay 或 alipay | alipay |
out_trade_no | 商户订单号 | String | 是 | 同一商户下唯一,最长 100 字符 | M202607150001 |
name | 商品名称 | String | 是 | 具体商品或服务名称,最长 120 字符 | 测试商品 |
money | 订单金额 | String | 是 | 单位元,大于 0,最多两位小数 | 1.00 |
notify_url | 异步通知地址 | String | 推荐 | 支付成功后平台发起 GET 通知 | https://merchant.example.com/pay/notify |
return_url | 页面跳转地址 | String | 否 | 用户完成支付后的浏览器跳转地址 | https://merchant.example.com/pay/return |
method | 接口模式 | String | 否 | web 或 jump,默认 web | web |
scene | 支付场景 | String | 否 | web 或 miniapp,默认 web | web |
channel_id | 支付配置 ID | Integer | 否 | 指定已启用的支付配置,不传则自动路由 | 12 |
clientip | 用户 IP | String | 否 | 发起支付的真实客户端 IP | 203.0.113.10 |
buyer_id | 买家标识 | String | 否 | JSAPI 或小程序支付需要时传入 | openid_or_buyer_id |
param | 扩展参数 | String | 否 | 通知时原样返回,最长 500 字符 | order_source=shop |
sign_type | 签名类型 | String | 是 | 固定为 MD5 | MD5 |
sign | 请求签名 | String | 是 | 32 位小写 MD5 | 202cb962ac59075b964b07152d234b70 |
curl -X POST 'https://czf.xxoi.cn/mapi.php' \
-d 'pid=1001' \
-d 'type=alipay' \
-d 'out_trade_no=M202607150001' \
-d 'name=测试商品' \
-d 'money=1.00' \
-d 'notify_url=https://merchant.example.com/pay/notify' \
-d 'sign_type=MD5' \
-d 'sign=<MD5_SIGN>'{
"code": 1,
"msg": "success",
"trade_no": "API202607150001",
"payurl": "https://pay.example.com/openapi/pay/API202607150001"
}{
"code": -1,
"msg": "签名校验失败"
}返回字段
| 字段 | 名称 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
code | 返回状态码 | Integer | 1 表示成功,-1 表示失败 | 1 |
msg | 返回信息 | String | 成功或失败原因 | success |
trade_no | 平台订单号 | String | 平台生成的 API 订单号 | API202607150001 |
payurl | 支付链接 | String | pay_type 非二维码时返回 | https://pay.example.com/openapi/pay/... |
qrcode | 二维码内容 | String | 扫码支付时返回 | https://qr.example.com/... |
- out_trade_no 在同一商户下必须唯一;重复请求会返回原订单,不能更换支付场景或支付配置。
- 商品金额使用元,必须大于 0,最多保留两位小数。
- method=jump 固定返回统一支付页;method=web 根据支付方式返回支付链接或二维码。
V1 订单查询
使用平台订单号或商户订单号查询订单,两个订单号至少传一个。
请求参数
| 参数 | 名称 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
act | 操作类型 | String | 是 | 固定为 order | order |
pid | 商户 ID | String | 是 | 用户中心 API 信息中的商户 ID | 1001 |
key | MD5 密钥 | String | 是 | 仅限服务端查询使用 | <MD5_KEY> |
trade_no | 平台订单号 | String | 二选一 | 平台生成的 API 订单号 | API202607150001 |
out_trade_no | 商户订单号 | String | 二选一 | 商户提交的唯一订单号 | M202607150001 |
curl 'https://czf.xxoi.cn/api.php?act=order&pid=1001&key=<MD5_KEY>&out_trade_no=M202607150001'{
"code": 1,
"msg": "查询订单号成功!",
"pid": 1001,
"trade_no": "API202607150001",
"out_trade_no": "M202607150001",
"api_trade_no": "2026071500001",
"type": "alipay",
"name": "测试商品",
"money": "1.00",
"status": 1,
"trade_status": "TRADE_SUCCESS",
"addtime": "2026-07-15 10:00:00",
"endtime": "2026-07-15 10:00:08",
"buyer": "buyer_001",
"param": "order_source=shop"
}{
"code": -1,
"msg": "订单不存在"
}返回字段
| 字段 | 名称 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
pid | 商户 ID | String | 订单所属商户 | 1001 |
trade_no | 平台订单号 | String | 平台生成的订单号 | API202607150001 |
out_trade_no | 商户订单号 | String | 商户提交的订单号 | M202607150001 |
api_trade_no | 支付机构交易号 | String | 微信或支付宝交易号,未支付时为空 | 2026071500001 |
type | 支付方式 | String | wxpay 或 alipay | alipay |
name | 商品名称 | String | 下单时提交的商品名称 | 测试商品 |
money | 订单金额 | String | 单位元 | 1.00 |
status | 支付状态 | Integer | 1 已支付,0 未支付 | 1 |
trade_status | 交易状态 | String | TRADE_SUCCESS、WAIT_BUYER_PAY 或 TRADE_CLOSED | TRADE_SUCCESS |
addtime | 创建时间 | String | 订单创建时间 | 2026-07-15 10:00:00 |
endtime | 支付时间 | String | 未支付时为空 | 2026-07-15 10:00:08 |
buyer | 买家标识 | String | openid、buyer_id 或客户端标识 | buyer_001 |
param | 扩展参数 | String | 下单时提交的 param | order_source=shop |
- 同时传 trade_no 和 out_trade_no 时优先使用 trade_no。
- 查询接口中的 key 是完整 MD5 密钥,只能由服务端调用。
V1 订单退款
根据平台订单号或商户订单号通过开放 API 发起原路退款。调用前需在用户中心 API 信息中开启退款 API。
请求参数
| 参数 | 名称 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
act | 操作类型 | String | 是 | 固定为 refund,并参与 MD5 签名 | refund |
pid | 商户 ID | String | 是 | 用户中心 API 信息中的商户 ID | 1001 |
trade_no | 平台订单号 | String | 二选一 | 与商户订单号至少传一个,同时传入时优先使用 | API202607150001 |
out_trade_no | 商户订单号 | String | 二选一 | 商户下单时提交的订单号 | M202607150001 |
money | 退款金额 | String | 是 | 单位元,大于 0,最多两位小数 | 1.00 |
out_refund_no | 商户退款单号 | String | 推荐 | 最长 100 字符,仅支持字母、数字、下划线和短横线;用于退款幂等 | MR202607150001 |
reason | 退款原因 | String | 否 | 最长 80 字符,默认 API退款 | 用户申请退款 |
return_profit_sharing | 回退分账 | Integer | 否 | 1 表示同时回退已执行分账,默认 0 | 0 |
profit_sharing_refund_money | 分账退款金额 | String | 条件 | return_profit_sharing=1 时可填写,单位元 | 0.00 |
sign_type | 签名类型 | String | 是 | 固定为 MD5 | MD5 |
sign | 请求签名 | String | 是 | 32 位小写 MD5 | <MD5_SIGN> |
curl -X POST 'https://czf.xxoi.cn/api.php?act=refund' \
-d 'pid=1001&trade_no=API202607150001&money=1.00&out_refund_no=MR202607150001&reason=用户申请退款&sign_type=MD5&sign=<MD5_SIGN>'{
"code": 1,
"msg": "退款申请已提交",
"refund_no": "RF202607150001",
"out_refund_no": "MR202607150001",
"trade_no": "API202607150001",
"out_trade_no": "M202607150001",
"money": "1.00",
"reducemoney": "0.00",
"status": 2,
"refund_status": "PROCESSING",
"reason": "用户申请退款",
"addtime": "2026-07-15 10:10:00",
"endtime": ""
}{
"code": -1,
"msg": "今日API退款笔数已达到上限(1笔)"
}返回字段
| 字段 | 名称 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
code | 返回状态码 | Integer | 1 成功,-1 失败 | 1 |
msg | 返回信息 | String | 处理结果或失败原因 | 退款申请已提交 |
refund_no | 平台退款单号 | String | 平台生成的唯一退款单号 | RF202607150001 |
out_refund_no | 商户退款单号 | String | 商户提交的退款单号;未提交时返回平台生成值 | MR202607150001 |
trade_no | 平台订单号 | String | 原支付订单的平台订单号 | API202607150001 |
out_trade_no | 商户订单号 | String | 原支付订单的商户订单号 | M202607150001 |
money | 退款金额 | String | 单位元 | 1.00 |
reducemoney | 扣减余额 | String | 当前系统原路退款不额外扣减账户余额,固定为 0.00 | 0.00 |
status | 退款状态码 | Integer | 0 失败、1 成功、2 处理中 | 2 |
refund_status | 退款状态 | String | PENDING、PROCESSING、SUCCESS、FAILED 或 CLOSED | PROCESSING |
reason | 退款原因 | String | 商户提交的退款原因 | 用户申请退款 |
failure_reason | 失败原因 | String | 退款失败时返回支付机构的失败原因,其他状态为空 | 退款单不存在(REFUNDNOTEXIST) |
addtime | 创建时间 | String | 退款记录创建时间 | 2026-07-15 10:10:00 |
endtime | 完成时间 | String | 成功或失败后的更新时间,处理中为空 |
- 同时传 trade_no 和 out_trade_no 时优先使用 trade_no。
- out_refund_no 在同一商户下唯一;相同退款单号、订单和金额的重复请求返回原结果,不会重复退款或重复计算每日额度。
- 每日最大退款笔数按退款记录创建时间统计,0 表示不限制;只统计待处理、处理中和成功的 API 退款,失败记录不占用当天笔数。
- status=1 表示成功,status=2 表示处理中,status=0 表示失败。微信退款可能先返回处理中,请通过退款查询接口获取最终状态。
- V1 退款必须使用 MD5 签名,不能使用订单查询接口的 key 参数代替签名。
V1 退款查询
使用平台退款单号或商户退款单号查询退款状态,两个退款单号至少传一个。
请求参数
| 参数 | 名称 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
act | 操作类型 | String | 是 | 固定为 refundquery,并参与 MD5 签名 | refundquery |
pid | 商户 ID | String | 是 | 用户中心 API 信息中的商户 ID | 1001 |
refund_no | 平台退款单号 | String | 二选一 | 平台返回的退款单号 | RF202607150001 |
out_refund_no | 商户退款单号 | String | 二选一 | 发起退款时提交或平台返回的商户退款单号 | MR202607150001 |
sign_type | 签名类型 | String | 是 | 固定为 MD5 | MD5 |
sign | 请求签名 | String | 是 | 32 位小写 MD5 | <MD5_SIGN> |
curl -X POST 'https://czf.xxoi.cn/api.php?act=refundquery' \
-d 'pid=1001&out_refund_no=MR202607150001&sign_type=MD5&sign=<MD5_SIGN>'{
"code": 1,
"msg": "查询退款成功!",
"refund_no": "RF202607150001",
"out_refund_no": "MR202607150001",
"trade_no": "API202607150001",
"out_trade_no": "M202607150001",
"money": "1.00",
"reducemoney": "0.00",
"status": 1,
"refund_status": "SUCCESS",
"reason": "用户申请退款",
"failure_reason": "",
"addtime": "2026-07-15 10:10:00",
"endtime": "2026-07-15 10:10:06"
}{
"code": -1,
"msg": "退款记录不存在"
}返回字段
| 字段 | 名称 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
code | 返回状态码 | Integer | 1 成功,-1 失败 | 1 |
msg | 返回信息 | String | 处理结果或失败原因 | 退款申请已提交 |
refund_no | 平台退款单号 | String | 平台生成的唯一退款单号 | RF202607150001 |
out_refund_no | 商户退款单号 | String | 商户提交的退款单号;未提交时返回平台生成值 | MR202607150001 |
trade_no | 平台订单号 | String | 原支付订单的平台订单号 | API202607150001 |
out_trade_no | 商户订单号 | String | 原支付订单的商户订单号 | M202607150001 |
money | 退款金额 | String | 单位元 | 1.00 |
reducemoney | 扣减余额 | String | 当前系统原路退款不额外扣减账户余额,固定为 0.00 | 0.00 |
status | 退款状态码 | Integer | 0 失败、1 成功、2 处理中 | 2 |
refund_status | 退款状态 | String | PENDING、PROCESSING、SUCCESS、FAILED 或 CLOSED | PROCESSING |
reason | 退款原因 | String | 商户提交的退款原因 | 用户申请退款 |
failure_reason | 失败原因 | String | 退款失败时返回支付机构的失败原因,其他状态为空 | 退款单不存在(REFUNDNOTEXIST) |
addtime | 创建时间 | String | 退款记录创建时间 | 2026-07-15 10:10:00 |
endtime | 完成时间 | String | 成功或失败后的更新时间,处理中为空 |
- 同时传 refund_no 和 out_refund_no 时优先使用 refund_no。
- 退款查询不受退款 API 开关和每日笔数上限影响,关闭退款接口后仍可查询历史退款。
- 微信处理中退款会主动查询微信侧状态;网关临时不可用时返回本地最近一次状态。
- V1 请求中的 act=refundquery 必须参与 MD5 签名。
V1 支付结果通知
订单支付成功后,平台通过 GET 请求向下单时提交的 notify_url 发送结果。
通知参数
| 参数 | 名称 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
pid | 商户 ID | String | 订单所属商户 | 1001 |
trade_no | 平台订单号 | String | 平台生成的订单号 | API202607150001 |
out_trade_no | 商户订单号 | String | 商户提交的订单号 | M202607150001 |
api_trade_no | 支付机构交易号 | String | 微信或支付宝交易号,未支付时为空 | 2026071500001 |
type | 支付方式 | String | wxpay 或 alipay | alipay |
name | 商品名称 | String | 下单时提交的商品名称 | 测试商品 |
money | 订单金额 | String | 单位元 | 1.00 |
trade_status | 交易状态 | String | TRADE_SUCCESS、WAIT_BUYER_PAY 或 TRADE_CLOSED | TRADE_SUCCESS |
addtime | 创建时间 | String | 订单创建时间 | 2026-07-15 10:00:00 |
endtime | 支付时间 | String | 未支付时为空 | 2026-07-15 10:00:08 |
buyer | 买家标识 | String | openid、buyer_id 或客户端标识 | buyer_001 |
param | 扩展参数 | String | 下单时提交的 param | order_source=shop |
sign_type | 签名类型 | String | 固定为 MD5 | MD5 |
sign | 通知签名 | String | 使用 MD5 密钥验签 | 202cb962ac59075b964b07152d234b70 |
success处理要求
- 1
先验证签名,再核对商户订单号、支付状态和订单金额。
- 2
使用数据库唯一键保证通知幂等,同一订单可能收到多次通知。
- 3
业务处理完成后返回纯文本 success,不要附加 HTML、JSON 或其他字符。
- 4
平台在 8 秒内未收到 success 会判定本次通知失败。
首次通知在支付成功后立即发送;失败后按 1、2、5、10 分钟重试,最多重试 4 次,总通知次数为 5 次。收到 success 后立即停止重试。
$params = $_GET;
$received = strtolower((string) ($params['sign'] ?? ''));
unset($params['sign'], $params['sign_type']);
$expected = md5(buildSignContent($params) . $md5Key);
if (!hash_equals($expected, $received)) { http_response_code(400); exit('fail'); }
// 使用 out_trade_no 做幂等处理并核对 money
echo 'success';错误说明与联调检查
接口失败时返回 code=-1 和具体 msg,以下为常见问题。
| 错误信息 | 原因 | 处理方式 |
|---|---|---|
| 请求参数为空 / 缺少商户ID | 未提交参数或 pid 缺失 | 检查请求格式和 pid |
| 签名校验失败 | 参与签名参数、排序、密钥或私钥不一致 | 打印待签名字符串逐项对比 |
| 请求时间戳无效或已过期 | V2 时间差超过 600 秒 | 开启服务器 NTP 时间同步 |
| 当前商户未启用该支付方式 | 没有启用对应支付配置 | 在支付配置中启用微信或支付宝 |
| 当前支付金额暂无可用支付通道 | 金额超出通道限制或路由无可用配置 | 检查最小金额、最大金额、单日限额和路由 |
| 请先完成实名认证后使用该功能 | 平台开启了商户强制认证 | 完成实名认证后重新发起支付 |
| 商户订单号已存在 | 相同订单号更换了场景或支付配置 | 每笔业务使用稳定且唯一的订单号 |
| 退款API接口未开启 | 用户关闭了退款 API 开关 | 在用户中心 API 信息中开启退款 API |
| 今日API退款笔数已达到上限 | 当天待处理、处理中和成功的 API 退款记录达到配置上限 | 次日再试或调整每日最大退款笔数 |
| 商户退款单号已存在,且退款订单或金额不一致 | 重复使用退款单号但请求内容发生变化 | 同一退款请求保持订单号和金额完全一致 |
上线前检查
- 1
使用正式域名和 HTTPS notify_url。
- 2
验证重复通知不会重复发货或重复入账。
- 3
确认 MD5 密钥只保存在服务端。
- 4
使用真实的 0.01 元以上测试订单完成全流程联调。
