接口对接说明
本文档提供外部系统对接支付平台的完整接口说明,包括发起支付、订单查询、退款等功能。
接口域名:正在读取...
签名算法:仅支持 ECDSA。旧版 MD5、RSA 及 /mapi.php?act=* 文档均已废弃,不可继续使用。
接口说明
支付产品由通道插件的已选可用接口决定。显式 method 只能请求该接口已开启的产品,平台不会在 Native、H5、JSAPI、小程序和 APP 之间猜测或降级。
/mapi.php请求方式:POST 推荐等价兼容入口
/api/pay/create、/openapi/order/pay/create 与 /mapi.php 调用同一服务,均兼容 GET/POST。新对接建议使用 POST。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
pid | string | 是 | 平台商户UID(商户后台显示的UID,如:100001 或 UWM3HK58) |
type | string | 是 | 支付类型,如 wxpay、alipay |
out_trade_no | string | 是 | 商户订单号,需唯一 |
notify_url | string | 是 | 异步通知地址 |
name | string | 是 | 支付标题;未传 original_name 时也作为商品名称显示 |
money | float | 是 | 支付金额(元) |
timestamp | int | 是 | 当前时间戳(秒) |
sign | string | 是 | ECDSA签名 |
sign_type | string | 是 | 签名类型,固定为 ECDSA |
app_id | string | 是 | 商户后台应用列表中的完整应用ID,不能自行拼接 |
original_name | string | 否 | 原商品名称;传入后订单详情会额外展示商品标题 |
return_url | string | 否 | 同步跳转地址 |
param | string | 否 | 自定义参数,回调时原样返回 |
clientip | string | 否 | 用户IP地址;不传时使用请求来源IP |
device | string | 否 | 用户实际终端:pc/mobile/wechat/alipay/qq/douyin/app |
method | string | 否 | web、jump、cashier、qrcode、h5、jsapi、scan、applet、app |
auth_code | string | 否 | 付款码;method=scan 时必填 |
sub_openid | string | 否 | 用户 OpenID;method=jsapi 时必填 |
sub_appid | string | 否 | 服务商/子商户模式下的子应用 AppID |
is_applet | int | 否 | 小程序上下文标记,method=applet 时平台自动设为 1 |
app_id 取值说明
app_id必须传商户后台“应用列表”里生成的完整应用ID,不能用 app_ + pid、商户UID、进件商户号或数据库内部ID代替。修改任何参与签名的参数后必须重新生成 sign。
请求示例
POST {origin}/mapi.php
Content-Type: application/x-www-form-urlencoded
pid=100001
&type=wxpay
&out_trade_no=ORDER202401010001
¬ify_url=https://your-site.com/notify
&return_url=https://your-site.com/return
&name=测试商品
&money=0.01
&app_id=app_xxxxxxxxxxxxxxxxxxxxxxxx
&device=pc
&method=web
×tamp=1704067200
&sign=MEUCIQDxxxxxx...
&sign_type=ECDSA
PC 微信自建收银台请使用 web
客户网站自己展示微信二维码时,传 type=wxpay、method=web、device=pc,并根据响应 type处理。返回 qrcode时只绘制二维码,不跳转 pay_url;需要平台托管收银台时使用 method=jump。
支付产品与二维码展示策略
服务器调用必须传递用户真实终端
device描述最终付款用户环境,不是发起 HTTP 请求的服务器。微信内传 wechat,支付宝内传 alipay。
接入模式选择
| 场景 | method | device | 调用方处理 |
|---|---|---|---|
| 浏览器付款 | jump | 用户真实终端 | 跳转 pay_url;用户可再次打开同一地址继续付款 |
| 插件自动选择产品 | web | 用户真实终端 | 按响应 type 消费;产品服从通道已选可用接口 |
| 自建 Native 扫码页 | qrcode | 通常为 pc | 把 qrcode 绘制成二维码,禁止当网页打开 |
| 始终展示收银台二维码 | cashier | 通常为 pc | 扫码后按已选接口完成真实支付 |
| 手机浏览器 H5 | h5 | mobile | 按 type 处理跳转地址或插件声明的结果 |
| 微信/支付宝内 JSAPI | jsapi | wechat/alipay | 传 sub_openid,使用 data 调用客户端 SDK |
| 微信小程序 | applet | 使用 data 调用小程序支付 API | |
| 原生 APP | app | app | 使用 data 调用支付 SDK |
| 商户扫用户付款码 | scan | 实际终端 | 必须传 auth_code,按同步结果处理 |
cashier、qrcode、scan 含义不同
cashier是始终展示二维码的展示策略;qrcode明确请求 Native/主扫二维码;scan是付款码/被扫支付,必须传 auth_code。无 auth_code 的旧 scan 请求目前临时兼容为 qrcode,但对接方不应继续依赖。
| method | 用途 | 约束 |
|---|---|---|
web | 默认直接调用插件,按 apptype 与终端选择产品 | - |
jump | 只返回本站 /pay/submit 收银台地址 | - |
cashier | 只展示一个二维码,真实产品仍服从 apptype | - |
qrcode | Native/主扫二维码 | 通道已开启扫码接口 |
h5 | 手机浏览器 H5 支付 | 通道已开启 H5 接口 |
jsapi | 微信/支付宝内 JSAPI | sub_openid |
scan | 商户扫描用户付款码 | auth_code |
applet | 小程序支付 | 通道已开启小程序接口 |
app | APP 支付参数 | 通道已开启 APP 接口 |
PC 微信扫码响应示例
{
"code": 0,
"msg": "success",
"type": "qrcode",
"trade_no": "20240101120000123456",
"pay_url": "weixin://wxpay/bizpayurl?pr=xxxxxxxx",
"qrcode": "weixin://wxpay/bizpayurl?pr=xxxxxxxx",
"page": "wxpay_qrcode",
"timestamp": 1704067200,
"sign": "MEUCIQDxxxxxx...",
"sign_type": "ECDSA"
}
响应类型
| 响应 type | 主要字段 | 正确处理方式 |
|---|---|---|
jump | pay_url | 浏览器跳转或 HTTP 重定向 |
qrcode | qrcode | 使用二维码库绘制,禁止 window.location 跳转 |
scheme | urlscheme | 由用户操作触发 Scheme,保留可重复点击入口 |
jsapi | data | 调用微信或支付宝 JSAPI |
app | data | 交给原生 APP 支付 SDK |
wxplugin / wxapp | data | 交给微信插件或小程序接口 |
scan | data | 读取同步结果,并以异步通知为最终依据 |
page | page + data | 插件页面结果;通用浏览器优先 method=jump |
响应类型以插件返回为准
平台保留插件声明的 qrcode/jump/scheme/jsapi/app/scan/wxplugin/wxapp/page 类型。URL类响应读取 pay_url、qrcode或 urlscheme;参数类响应读取 data。二维码结果还可能声明 scan_only、direct_open、wechat_direct_open、android_wechat_direct_open,只有对应能力明确为真时才允许特定终端直开。
不要把二维码内容当网页地址打开
qrcode可能是微信 Native 码、支付宝扫码串或第三方扫码内容,只能由二维码库绘制;只有 type=jump 时才跳转 pay_url。
// 错误:二维码内容不是网页地址
window.location.href = result.qrcode
// 正确:二维码模式只绘制二维码
if (result.type === 'qrcode') {
QRCode.toCanvas(canvas, result.qrcode)
}
// 正确:jump 模式才跳转托管收银台
if (result.type === 'jump') {
window.location.assign(result.pay_url)
}
支付响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0 表示成功 |
msg | string | 结果说明 |
type | string | 必须按类型分支处理 |
trade_no | string | 平台订单号 |
pay_url | string | 是否可跳转以 type 为准 |
qrcode | string | 二维码原始内容,仅用于绘制 |
urlscheme | string | 仅在 type=scheme 时使用 |
data | object|string | JSAPI、小程序、APP、付款码参数 |
page | string | 插件声明的页面模板标识 |
scan_only | boolean | 为 true 时保持二维码展示 |
direct_open | boolean | 插件明确允许普通终端直接打开 |
wechat_direct_open | boolean | 插件明确允许微信内直接打开 |
android_wechat_direct_open | boolean | 插件明确允许 Android 微信内直接打开 |
timestamp | int | 平台响应时间戳 |
sign | string | 平台 ECDSA 响应签名 |
sign_type | string | 固定为 ECDSA |
成功响应示例
{
"code": 0,
"msg": "success",
"type": "jump",
"trade_no": "20240101120000123456",
"pay_url": "{origin}/pay/submit/20240101120000123456",
"timestamp": 1704067200,
"sign": "MEUCIQDxxxxxx...",
"sign_type": "ECDSA"
}
错误响应
{
"code": -1,
"msg": "错误信息"
}
注意事项
method=jump返回本站收银台地址。method=web由插件按已选 apptype 决定产品。method=scan必须携带付款码 auth_code。- 同一商户订单号在10天内不可重复使用。
- 时间戳误差不能超过5分钟。
接口说明
查询订单的支付状态和详细信息。
/api.php?s=pay/query请求方式:POST 推荐等价兼容入口
/api/pay/query、/openapi/order/pay/query 与上述地址调用同一查询服务。
接口范围说明
- 只能按
trade_no或out_trade_no查询单个订单。 - 当前未提供对外分页订单列表 API。
- 请求和返回验签仅支持 ECDSA。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
pid | string | 是 | 平台商户UID |
trade_no | string | 二选一 | 平台订单号 |
out_trade_no | string | 二选一 | 商户订单号 |
timestamp | int | 是 | 当前时间戳 |
sign | string | 是 | ECDSA签名 |
sign_type | string | 是 | 固定 ECDSA |
成功响应
{
"code": 0,
"msg": "success",
"trade_no": "20240101120000123456",
"out_trade_no": "ORDER202401010001",
"type": "wxpay",
"pid": "100001",
"addtime": "2024-01-01 12:00:00",
"endtime": "2024-01-01 12:05:00",
"name": "测试商品",
"money": "0.01",
"param": "{\"user_param\":\"your_custom_param\"}",
"status": 1,
"timestamp": 1704067200,
"sign": "MEUCIQDxxxxxx...",
"sign_type": "ECDSA"
}
param 字段说明
param返回订单原始存储格式(JSON字符串),自定义参数存储在 user_param字段中;平台也可能附带 aggregate_merchant、aggregate_merchant_id、apply_merchant_id、merchant_config等系统字段。
订单状态说明
| 状态值 | 说明 |
|---|---|
| 0 | 未支付 |
| 1 | 已支付 |
| -1 | 已取消/已过期 |
| 2 | 已完成(历史状态) |
| 3 | 已退款 |
当前版本未开放分页订单列表接口
当前外部商户 API 仅提供发起支付、单笔订单查询、订单退款和支付结果通知。如需批量对账,请使用商户后台订单管理、账单对账或基于异步通知自行落库。
请勿使用旧版接口
以下旧版接口已废弃,请不要继续对接:
POST {origin}/mapi.php?act=order
POST {origin}/mapi.php?act=orders
旧版 MD5 / 密钥拼接签名规则也已废弃,当前仅支持 ECDSA。
接口说明
对已支付的订单发起退款申请。
/api.php?s=pay/refund请求方式:POST 推荐等价兼容入口
/api/pay/refund、/openapi/order/pay/refund与上述地址调用同一退款服务。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
pid | string | 是 | 平台商户UID |
trade_no | string | 二选一 | 平台订单号 |
out_trade_no | string | 二选一 | 商户订单号 |
money | float | 否 | 退款金额,不传则全额退款 |
request_no | string | 否 | 商户退款请求号,建议唯一 |
timestamp | int | 是 | 当前时间戳 |
sign | string | 是 | ECDSA签名 |
sign_type | string | 是 | 固定 ECDSA |
注意事项
- 只有已支付订单才能退款。
- 退款金额不能超过实际支付金额。
- 部分支付渠道可能不支持部分退款。
成功响应
{
"code": 0,
"msg": "退款成功",
"trade_no": "20240101120000123456",
"out_trade_no": "ORDER202401010001",
"refund_money": "0.01",
"timestamp": 1704067200,
"sign": "MEUCIQDxxxxxx...",
"sign_type": "ECDSA"
}
接口说明
用户支付成功后,平台向商户设置的 notify_url 发送异步通知;商户必须验证签名后处理业务。
通知参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
pid | string | 是 | 平台商户UID |
trade_no | string | 是 | 平台订单号 |
out_trade_no | string | 是 | 商户订单号 |
type | string | 是 | 支付类型 |
name | string | 是 | 商品名称 |
money | float | 是 | 支付金额 |
trade_status | string | 是 | TRADE_SUCCESS |
param | string | 否 | 自定义参数 |
timestamp | int | 是 | 时间戳 |
sign | string | 是 | 平台ECDSA签名 |
sign_type | string | 是 | ECDSA |
通知示例
POST https://your-site.com/notify
Content-Type: application/x-www-form-urlencoded
pid=100001
&trade_no=20240101120000123456
&out_trade_no=ORDER202401010001
&type=wxpay
&name=测试商品
&money=0.01
&trade_status=TRADE_SUCCESS
¶m=
×tamp=1704067200
&sign=MEUCIQDxxxxxx...
&sign_type=ECDSA
处理流程
- 接收通知参数。
- 使用平台公钥验证 ECDSA 签名。
- 验证订单金额。
- 检查订单是否已处理。
- 更新订单状态。
- 返回纯文本
success。
重要提示
- 必须返回纯文本
success(不含引号),否则平台会重复通知。 - 务必验证签名和订单金额。
- 业务处理必须幂等。
ECDSA 签名说明
本平台采用 ECDSA(椭圆曲线数字签名算法)进行请求、响应和通知签名验证。
签名步骤
第一步:筛选参数
移除 sign 和 sign_type,过滤空值参数。
第二步:排序参数
按参数名 ASCII 码从小到大排序。
第三步:拼接字符串
按 key=value 格式使用 & 连接;数组值使用 JSON_UNESCAPED_UNICODE。
第四步:生成签名
使用商户私钥对拼接字符串执行 ECDSA-SHA256 签名,再进行 Base64 编码。
PHP 签名示例
function makeSign($params, $privateKey) {
unset($params['sign'], $params['sign_type']);
$params = array_filter($params, function($v) {
return $v !== '' && $v !== null;
});
ksort($params);
$pairs = [];
foreach ($params as $key => $value) {
if (is_array($value)) $value = json_encode($value, JSON_UNESCAPED_UNICODE);
$pairs[] = $key . '=' . $value;
}
$signStr = implode('&', $pairs);
openssl_sign($signStr, $signature, openssl_pkey_get_private($privateKey), OPENSSL_ALGO_SHA256);
return base64_encode($signature);
}
验证签名(验证平台通知)
function verifySign($params, $platformPublicKey) {
$sign = $params['sign'] ?? '';
unset($params['sign'], $params['sign_type']);
$params = array_filter($params, function($v) {
return $v !== '' && $v !== null;
});
ksort($params);
$pairs = [];
foreach ($params as $key => $value) {
if (is_array($value)) $value = json_encode($value, JSON_UNESCAPED_UNICODE);
$pairs[] = $key . '=' . $value;
}
$signStr = implode('&', $pairs);
return openssl_verify($signStr, base64_decode($sign), openssl_pkey_get_public($platformPublicKey), OPENSSL_ALGO_SHA256) === 1;
}
密钥管理
- 商户私钥必须妥善保管,不能泄露。
- 平台公钥用于验证平台响应和异步通知。
- 商户在“API接口”页面生成和查看密钥。
错误码说明
| 错误码 | 说明 |
|---|---|
| 0 | 成功 |
| -1 | 系统错误或业务错误 |
| -2 | 参数错误 |
| -3 | 签名验证失败 |
| -4 | 未传入参数 |
| -5 | 接口不存在 |