商户 API 对接文档
版本 v1.2 · 最后更新:2026-04-10
一、接入准备
1.1 获取密钥
1登录商户后台
2进入「API管理」页面
3获取以下信息:
| 参数 | 说明 |
|---|---|
商户号 memberid | 平台分配的6位商户号 |
商户密钥 key | 用于签名的密钥,请妥善保管 |
网关地址 gateway | API请求的基础URL |
1.2 对接须知
| 项目 | 说明 |
|---|---|
| 请求方式 | 所有接口均使用 POST |
| 请求格式 | application/x-www-form-urlencoded 或 multipart/form-data |
| 字符编码 | UTF-8 |
| 签名方式 | HMAC-SHA256 |
| IP白名单 | 建议在商户后台配置回调IP白名单。未配置时允许所有IP访问 |
| 金额格式 | 单位:元,保留2位小数,如 100.00 |
| 时间格式 | YYYY-MM-DD HH:mm:ss,如 2026-04-04 14:30:00 |
| 时间说明 | pay_applydate 为商户系统当前时间,任意时区均可,仅参与签名计算 |
二、签名算法
平台使用 HMAC-SHA256 签名算法:
| 签名类型 | 安全等级 | 说明 |
|---|---|---|
| HMAC-SHA256 | 高 | 64位签名 |
2.1 通用步骤
1筛选参与签名的字段,去除值为空的参数和签名字段(
pay_sign)本身。2将剩余参数按照 参数名 ASCII 码从小到大排序(字典序),使用 URL 键值对的格式拼接。
3使用 HMAC-SHA256 算法计算签名:
HMAC-SHA256
sign = HMAC_SHA256(stringA, 商户密钥).toUpperCase()密钥作为 HMAC 的 key 参数,不拼接在字符串末尾。
2.2 签名示例
假设参数如下:
pay_memberid = "100001"
pay_orderid = "20260404143000001"
pay_applydate = "2026-04-04 14:30:00"
pay_notifyurl = "https://merchant.com/notify"
pay_callbackurl = "https://merchant.com/callback"
pay_amount = "500.00"
商户密钥 = "a1b2c3d4e5f6..."拼接后(按参数名ASCII排序):
stringA = "pay_amount=500.00&pay_applydate=2026-04-04 14:30:00&pay_callbackurl=https://merchant.com/callback&pay_memberid=100001&pay_notifyurl=https://merchant.com/notify&pay_orderid=20260404143000001"
注意事项
值为空的参数不参与签名 · 签名字段本身不参与签名 · 中文参数不需要URL编码后再签名 · 参数值前后不要有空格
三、代收 API
3.1 代收下单
商户发起收款请求,平台匹配可用通道并返回收款信息。
POST{网关地址}/api/v1/gateway/pay
请求参数
| 参数名 | 含义 | 必填 | 签名 | 说明 |
|---|---|---|---|---|
pay_memberid | 商户号 | Y | Y | 平台分配的商户号 |
pay_orderid | 商户订单号 | Y | Y | 商户系统唯一订单号,最长50字符 |
pay_applydate | 提交时间 | Y | Y | 商户系统当前时间,格式:YYYY-MM-DD HH:mm:ss,任意时区均可,仅参与签名 |
pay_bankcode | 通道编码 | N | Y | 支付通道编码,不传则使用默认通道,参见通道编码表 |
pay_notifyurl | 服务端通知地址 | Y | Y | 支付成功后,平台通过POST异步通知此地址,必须为外网可访问的URL |
pay_callbackurl | 页面跳转地址 | Y | Y | 支付成功后,收银台页面自动跳转至此URL(5秒倒计时) |
pay_amount | 订单金额 | Y | Y | 单位元,保留2位小数,如 100.00 |
pay_productname | 商品名称 | N | N | 商品描述,可选参数 |
pay_ip | 付款人IP | N | N | 付款人的真实IP地址 |
pay_sign | 签名 | Y | - | 签名值,参见签名算法 |
pay_attach | 附加数据 | N | N | 原样返回,中文需URL编码 |
pay_userid | 会员ID | N | N | 商户系统内的用户唯一标识 |
pay_username | 付款人姓名 | N | N | 转卡或银联通道必填 |
请求示例
{
"pay_memberid": "100001",
"pay_orderid": "20260414100000001",
"pay_applydate": "2026-04-14 10:00:00",
"pay_notifyurl": "https://merchant.com/notify",
"pay_callbackurl": "https://merchant.com/success",
"pay_amount": "500.00",
"pay_username": "张三",
"pay_sign": "A1B2C3D4E5F6..."
}成功响应
{
"code": 200,
"message": "操作成功",
"data": {
"status": "1",
"msg": "下单成功",
"order_id": "C20260404143000123456",
"mch_order_id": "20260404143000001",
"pay_url": "/cashier/eyJhbGciOiJIUzI1NiJ9..."
},
"timestamp": 1775551800000
}| 参数 | 说明 |
|---|---|
code | HTTP状态码,200 为成功 |
message | 操作结果描述 |
data.status | "1" 为成功 |
data.msg | 状态描述信息 |
data.order_id | 平台系统订单号(C开头=代收) |
data.mch_order_id | 商户订单号(原样返回 pay_orderid) |
data.pay_url | 收银台页面相对路径,需拼接网关域名后引导付款人访问 |
timestamp | 服务端时间戳(毫秒) |
常见错误
{
"code": 403,
"message": "签名错误",
"data": null,
"timestamp": 1775551851034
}| code | message | 原因 |
|---|---|---|
| 403 | 签名错误 | 签名算法不正确或密钥错误 |
| 404 | 商户不存在 | 商户号错误 |
| 403 | 商户已禁用 | 商户被平台禁用 |
| 403 | 商户代收功能未开启 | 商户未开启收款功能 |
| 403 | IP不在白名单中 | 请求IP不在商户配置的白名单中 |
| 400 | 金额须在 X - Y 之间 | 金额低于最小或超过最大限额 |
| 404 | 暂无可用通道 | 当前无匹配的收款产品 |
| 429 | 请求过于频繁,请稍后再试 | 超出API频率限制 |
3.2 代收回调通知
付款人完成支付后,平台会向商户的 pay_notifyurl 发送POST异步通知。
POST商户的 pay_notifyurl 地址
回调参数
| 参数名 | 含义 | 签名 | 说明 |
|---|---|---|---|
memberid | 商户号 | Y | 平台分配的商户号 |
orderid | 商户订单号 | Y | 商户系统的订单号 |
amount | 订单金额 | Y | 实际支付金额,保留2位小数 |
transaction_id | 平台流水号 | Y | 平台生成的唯一交易流水号 |
datetime | 交易时间 | Y | 平台时区时间,格式 YYYY-MM-DD HH:mm:ss,如 2026-04-04 14:35:00 |
returncode | 交易状态 | Y | 00 表示支付成功 |
timestamp | 回调时间戳 | Y | Unix时间戳(秒),用于防重放校验 |
nonce | 随机串 | Y | 32位随机字符串,每次回调唯一 |
attach | 附加数据 | N | 下单时传入的附加字段,原样返回 |
sign | 签名 | - | 签名值,商户需验签确认通知合法性 |
商户响应要求
验签通过并处理业务逻辑后,商户需在HTTP响应体中返回纯文本:
OK
必须返回大写的 OK
无引号、无空格、无其他字符。如果平台未收到
OK 响应,将按 30秒 → 60秒 → 120秒 间隔重试3次。
安全校验建议
1. 检查 timestamp:当前时间 - timestamp > 300秒 → 拒绝(可能是重放攻击)
2. 检查 nonce:是否已处理过 → 已处理则直接返回OK
3. 回调可能重复发送,商户需做好幂等处理
2. 检查 nonce:是否已处理过 → 已处理则直接返回OK
3. 回调可能重复发送,商户需做好幂等处理
3.3 代收订单查询
主动查询代收订单的支付状态。
POST{网关地址}/api/v1/gateway/query
请求参数
| 参数名 | 含义 | 必填 | 签名 | 说明 |
|---|---|---|---|---|
pay_memberid | 商户号 | Y | Y | 平台分配的商户号 |
pay_orderid | 商户订单号 | Y | Y | 需要查询的商户订单号 |
pay_sign | 签名 | Y | - | 签名值 |
请求示例
{
"pay_memberid": "100001",
"pay_orderid": "20260414100000001",
"pay_sign": "A1B2C3D4E5F6..."
}响应参数
{
"code": 200,
"message": "操作成功",
"data": {
"memberid": "100001",
"orderid": "20260404143000001",
"amount": "500.00",
"time_end": "2026-04-04T14:35:00.000Z",
"transaction_id": "C20260404143000123456",
"returncode": "00",
"trade_state": "SUCCESS",
"sign": "A1B2C3D4..."
},
"timestamp": 1775551800000
}| 参数名 | 含义 | 签名 | 说明 |
|---|---|---|---|
data.memberid | 商户号 | Y | 平台分配的商户号 |
data.orderid | 商户订单号 | Y | 原样返回下单时的 pay_orderid |
data.amount | 订单金额 | Y | 保留2位小数,如 500.00 |
data.time_end | 支付完成时间 | Y | ISO 8601 格式,未支付时为空字符串 |
data.transaction_id | 平台流水号 | Y | 平台系统订单号(C开头=代收) |
data.returncode | 请求状态 | Y | 00=查询成功 / 01=未支付。仅表示查询请求状态,不代表已支付 |
data.trade_state | 交易状态 | Y | NOTPAY=待支付 / SUCCESS=已支付 / EXPIRED=已过期 |
data.sign | 签名 | - | 平台对响应参数的签名,商户可验签确认合法性 |
判断支付状态请使用
trade_state 字段,不要用 returncode
四、代付 API
4.1 代付下单
商户发起付款请求,平台将资金通过渠道转账至指定收款账户。
POST{网关地址}/api/v1/gateway/payout
请求参数
| 参数名 | 含义 | 必填 | 签名 | 说明 |
|---|---|---|---|---|
pay_memberid | 商户号 | Y | Y | 平台分配的商户号 |
pay_orderid | 商户订单号 | Y | Y | 商户系统唯一订单号,最长50字符 |
pay_applydate | 提交时间 | Y | Y | 商户系统当前时间,格式:YYYY-MM-DD HH:mm:ss,仅参与签名 |
pay_bankcode | 通道编码 | N | Y | 付款通道编码,不传则使用默认通道,参见通道编码表 |
pay_notifyurl | 服务端通知 | Y | Y | 付款完成后,平台通过POST异步通知此地址,必须为外网可访问的URL |
pay_amount | 付款金额 | Y | Y | 单位元,保留2位小数 |
pay_callbackurl | 页面跳转地址 | N | N | 付款完成后的前端跳转地址 |
pay_bank_name | 收款银行 | Y | Y | 如 中国工商银行 |
pay_account_name | 收款人姓名 | Y | Y | 收款方真实姓名 |
pay_account_no | 收款账号 | Y | Y | 收款方银行卡号 |
pay_sign | 签名 | Y | - | 签名值 |
pay_attach | 附加数据 | N | N | 原样返回 |
请求示例
{
"pay_memberid": "100001",
"pay_orderid": "20260414150000001",
"pay_applydate": "2026-04-14 15:00:00",
"pay_notifyurl": "https://merchant.com/notify",
"pay_amount": "1000.00",
"pay_bank_name": "中国工商银行",
"pay_account_name": "李四",
"pay_account_no": "6222021234567890123",
"pay_sign": "A1B2C3D4E5F6..."
}成功响应
{
"code": 200,
"message": "操作成功",
"data": {
"status": "1",
"msg": "下单成功",
"order_id": "P20260404150000654321",
"mch_order_id": "20260404150000001",
"amount": 1000,
"fee": 32
},
"timestamp": 1775551800000
}| 参数 | 说明 |
|---|---|
code | HTTP状态码,200 为成功 |
data.status | "1" 为成功 |
data.msg | 状态描述信息 |
data.order_id | 平台系统订单号(P开头=代付) |
data.mch_order_id | 商户订单号(原样返回 pay_orderid) |
data.amount | 付款金额 |
data.fee | 手续费金额(百分比费用 + 固定费用) |
timestamp | 服务端时间戳(毫秒) |
余额要求
代付需要商户预先充值。所需余额 = 付款金额 + 手续费。例如:付款1000元,费率3%+2,则需余额 ≥ 1032元。
4.2 代付回调通知
付款完成后,平台会向商户的 pay_notifyurl 发送POST异步通知。
POST商户的 pay_notifyurl 地址
回调参数
| 参数名 | 含义 | 签名 | 说明 |
|---|---|---|---|
memberid | 商户号 | Y | 平台分配的商户号 |
orderid | 商户订单号 | Y | 商户系统的订单号 |
amount | 付款金额 | Y | 实际付款金额,保留2位小数 |
transaction_id | 平台流水号 | Y | 平台生成的唯一交易流水号(P开头) |
datetime | 交易时间 | Y | 平台时区时间,格式 YYYY-MM-DD HH:mm:ss |
returncode | 交易状态 | Y | 见下方状态说明 |
timestamp | 回调时间戳 | Y | Unix时间戳(秒),用于防重放校验 |
nonce | 随机串 | Y | 32位随机字符串,每次回调唯一 |
attach | 附加数据 | N | 下单时传入的附加字段,原样返回 |
sign | 签名 | - | 签名值,商户需验签确认通知合法性 |
returncode 状态说明
| returncode | 含义 | 商户处理建议 |
|---|---|---|
00 | 付款成功 | 标记订单为付款完成 |
01 | 付款失败 | 联系平台客服排查原因 |
02 | 已取消 | 付款被取消,款项不会到账 |
商户响应要求 与代收回调相同,验签通过后需返回纯文本
OK(大写),否则平台重试3次。
4.3 代付订单查询
POST{网关地址}/api/v1/gateway/payout/query
请求参数
| 参数名 | 含义 | 必填 | 签名 |
|---|---|---|---|
pay_memberid | 商户号 | Y | Y |
pay_orderid | 商户订单号 | Y | Y |
pay_sign | 签名 | Y | - |
请求示例
{
"pay_memberid": "100001",
"pay_orderid": "20260414150000001",
"pay_sign": "A1B2C3D4E5F6..."
}响应示例
{
"code": 200,
"message": "操作成功",
"data": {
"memberid": "100001",
"orderid": "20260404150000001",
"amount": "1000.00",
"time_end": "2026-04-04T15:10:00.000Z",
"transaction_id": "P20260404150000654321",
"returncode": "00",
"trade_state": "SUCCESS",
"sign": "A1B2C3D4..."
},
"timestamp": 1775551800000
}| 参数名 | 含义 | 签名 | 说明 |
|---|---|---|---|
data.memberid | 商户号 | Y | 平台分配的商户号 |
data.orderid | 商户订单号 | Y | 原样返回下单时的 pay_orderid |
data.amount | 付款金额 | Y | 保留2位小数,如 1000.00 |
data.time_end | 付款完成时间 | Y | ISO 8601 格式,未完成时为空字符串 |
data.transaction_id | 平台流水号 | Y | 平台系统订单号(P开头=代付) |
data.returncode | 请求状态 | Y | 00=查询成功 / 01=未完成 |
data.trade_state | 交易状态 | Y | NOTPAY=待付款 / SUCCESS=已付款 / CANCELLED=已取消 / EXPIRED=已过期 |
data.sign | 签名 | - | 平台对响应参数的签名,商户可验签确认合法性 |
五、余额查询
POST{网关地址}/api/v1/gateway/balance
请求参数
| 参数名 | 含义 | 必填 | 签名 |
|---|---|---|---|
pay_memberid | 商户号 | Y | Y |
pay_orderid | 请求标识 | Y | Y |
pay_applydate | 查询时间 | Y | Y |
pay_sign | 签名 | Y | - |
请求示例
{
"pay_memberid": "100001",
"pay_orderid": "BAL20260414100000",
"pay_applydate": "2026-04-14 10:00:00",
"pay_sign": "A1B2C3D4E5F6..."
}响应示例
{
"code": 200,
"message": "操作成功",
"data": {
"status": "1",
"memberid": "100001",
"balance": "50000.00",
"frozen_balance": "3000.00"
},
"timestamp": 1775551800000
}| 参数 | 说明 |
|---|---|
code | HTTP状态码,200 为成功 |
data.status | "1" 为成功 |
data.memberid | 商户号 |
data.balance | 可用余额 |
data.frozen_balance | 冻结余额(进行中订单占用) |
余额查询接口响应不包含签名,仅在HTTPS环境下使用。
六、支付通道编码
| 通道编码 | 通道名称 | 类型 | 说明 |
|---|---|---|---|
BANK_CARD | 银行卡转卡 | 代收/代付 | 默认通道,代收时需填写 pay_username |
当前版本仅支持银行卡转卡通道。通道编码为可选参数,不传时默认使用银行卡通道。
七、签名示例代码
PHP
<?php
function createSign($params, $key) {
unset($params['pay_sign'], $params['sign']);
$params = array_filter($params, function($v) { return $v !== ''; });
ksort($params);
$stringA = '';
foreach ($params as $k => $v) {
$stringA .= $k . '=' . $v . '&';
}
$stringA = rtrim($stringA, '&');
return strtoupper(hash_hmac('sha256', $stringA, $key));
}
$params = [
'pay_memberid' => '100001',
'pay_orderid' => '20260404143000001',
'pay_applydate' => '2026-04-04 14:30:00',
'pay_notifyurl' => 'https://merchant.com/notify',
'pay_callbackurl' => 'https://merchant.com/callback',
'pay_amount' => '500.00',
];
$params['pay_sign'] = createSign($params, 'your_secret_key');
$ch = curl_init('https://platform.com/api/v1/gateway/pay');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public class PaySign {
public static String createSign(Map<String, String> params, String key) {
TreeMap<String, String> sorted = new TreeMap<>();
for (Map.Entry<String, String> e : params.entrySet()) {
if (!"pay_sign".equals(e.getKey()) && !"sign".equals(e.getKey())
&& e.getValue() != null && !e.getValue().isEmpty()) {
sorted.put(e.getKey(), e.getValue());
}
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : sorted.entrySet()) {
if (sb.length() > 0) sb.append("&");
sb.append(e.getKey()).append("=").append(e.getValue());
}
return hmacSha256(sb.toString(), key).toUpperCase();
}
private static String hmacSha256(String data, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"));
byte[] bytes = mac.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString();
} catch (Exception e) { throw new RuntimeException(e); }
}
}Python
import hashlib, hmac, requests
def create_sign(params: dict, key: str) -> str:
filtered = {k: v for k, v in params.items()
if k not in ('pay_sign', 'sign') and v}
sorted_keys = sorted(filtered.keys())
string_a = '&'.join(f'{k}={filtered[k]}' for k in sorted_keys)
return hmac.new(key.encode(), string_a.encode(), hashlib.sha256).hexdigest().upper()
params = {
'pay_memberid': '100001',
'pay_orderid': '20260404143000001',
'pay_applydate': '2026-04-04 14:30:00',
'pay_notifyurl': 'https://merchant.com/notify',
'pay_callbackurl': 'https://merchant.com/callback',
'pay_amount': '500.00',
}
params['pay_sign'] = create_sign(params, 'your_secret_key')
resp = requests.post('https://platform.com/api/v1/gateway/pay', data=params)
print(resp.json())Node.js
const crypto = require('crypto');
const axios = require('axios');
function createSign(params, key) {
const filtered = Object.entries(params)
.filter(([k, v]) => !['pay_sign', 'sign'].includes(k) && v !== '')
.sort(([a], [b]) => a.localeCompare(b));
const stringA = filtered.map(([k, v]) => `${k}=${v}`).join('&');
return crypto.createHmac('sha256', key)
.update(stringA, 'utf8').digest('hex').toUpperCase();
}
const params = {
pay_memberid: '100001',
pay_orderid: '20260404143000001',
pay_applydate: '2026-04-04 14:30:00',
pay_notifyurl: 'https://merchant.com/notify',
pay_callbackurl: 'https://merchant.com/callback',
pay_amount: '500.00',
};
params.pay_sign = createSign(params, 'your_secret_key');
axios.post('https://platform.com/api/v1/gateway/pay', new URLSearchParams(params))
.then(res => console.log(res.data));Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"sort"
"strings"
)
// CreateSign 生成签名
func CreateSign(params map[string]string, key string) string {
// 1. 过滤空值和签名字段,按 key 排序
keys := make([]string, 0)
for k, v := range params {
if k == "pay_sign" || k == "sign" || v == "" {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
// 2. 拼接参数
pairs := make([]string, 0, len(keys))
for _, k := range keys {
pairs = append(pairs, k+"="+params[k])
}
stringA := strings.Join(pairs, "&")
// 3. 计算签名
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(stringA))
return strings.ToUpper(hex.EncodeToString(mac.Sum(nil)))
}
func main() {
params := map[string]string{
"pay_memberid": "100001",
"pay_orderid": "20260404143000001",
"pay_applydate": "2026-04-04 14:30:00",
"pay_notifyurl": "https://merchant.com/notify",
"pay_callbackurl": "https://merchant.com/callback",
"pay_amount": "500.00",
}
secretKey := "your_secret_key"
params["pay_sign"] = CreateSign(params, secretKey)
// 发送请求
form := url.Values{}
for k, v := range params {
form.Set(k, v)
}
resp, err := http.PostForm("https://platform.com/api/v1/gateway/pay", form)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
buf := make([]byte, 4096)
n, _ := resp.Body.Read(buf)
fmt.Println("响应:", string(buf[:n]))
}回调验签示例 (Node.js)
// 生产环境用 Redis 存储已处理的 nonce,TTL 24小时
const processedNonces = new Set();
app.post('/notify', async (req, res) => {
const { sign, attach, ...signParams } = req.body;
// 1. 防重放:校验时间戳
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(signParams.timestamp)) > 300) {
return res.send('FAIL'); // 超过5分钟,可能是重放
}
// 2. 防重复:校验 nonce
if (processedNonces.has(signParams.nonce)) {
return res.send('OK'); // 已处理过,直接返回OK
}
// 3. 验签
const calculated = createSign(signParams, MERCHANT_KEY, 'HMAC-SHA256');
if (calculated !== sign) {
return res.send('FAIL'); // 签名不匹配
}
// 4. 验证交易状态
if (signParams.returncode !== '00') {
return res.send('FAIL');
}
// 5. 幂等:检查订单是否已处理
const order = await getOrder(signParams.orderid);
if (order.status === 'paid') {
processedNonces.add(signParams.nonce);
return res.send('OK');
}
// 6. 处理业务逻辑
await updateOrderStatus(signParams.orderid, 'paid', {
transactionId: signParams.transaction_id,
amount: signParams.amount,
paidAt: signParams.datetime,
});
// 7. 记录 nonce + 返回OK
processedNonces.add(signParams.nonce);
res.send('OK');
});八、常见问题
Q1: 签名一直不通过?
- 确认参与签名的字段是否正确(参见各接口的「参与签名」列)
- 确认排序是否按参数名 ASCII 码升序(不是按值排序)
- 确认空值参数是否已排除
- HMAC-SHA256:密钥是 HMAC 的 key,不拼在字符串里
- 确认结果已转为大写
- 打印签名前的拼接字符串,逐字符核对
Q2: 回调一直收不到?
- 检查
pay_notifyurl是否可从外网访问 - 检查服务器防火墙是否放行了平台IP
- 确认回调接口返回的是纯文本
OK,而非JSON或HTML - 主动调用订单查询接口确认订单状态
Q3: 下单返回"暂无可用通道"?
- 当前通道可能繁忙,请稍后重试
- 如传入了
pay_bankcode,确认编码是否正确 - 确认该通道是否已在商户后台启用
- 联系平台确认通道状态
Q4: 代付下单返回"余额不足"?
代付需要商户预先充值。所需余额 = 付款金额 + 手续费(百分比 + 固定费用)。
例如:付款1000元,费率3%+2,则需余额 ≥ 1000 + 30 + 2 = 1032元。
Q5: 订单超时了但用户已付款怎么办?
联系平台客服进行补单操作,平台确认到账后会重新回调通知。
附录:错误响应说明
所有错误响应格式统一为:
{
"code": 403,
"message": "签名错误",
"data": null,
"timestamp": 1775551851034
}其中 code 为 HTTP 状态码,message 为中文错误描述。常见错误如下:
| HTTP 状态码 | message | 原因 |
|---|---|---|
| 400 | 金额无效 | 金额为0、负数或非数字 |
| 400 | 金额须在 X - Y 之间 | 金额超出商户配置的范围 |
| 400 | xxx 必须是字符串 / 不能为空 | 必填参数缺失或类型错误 |
| 400 | 不允许的字段: xxx | 传入了接口未定义的参数 |
| 403 | 缺少商户号 | 未传 pay_memberid |
| 403 | 签名错误 | 签名算法或密钥不正确 |
| 403 | 商户已禁用 | 商户被平台禁用 |
| 403 | 商户代收功能未开启 | 商户后台未开启代收 |
| 403 | 商户代付功能未开启 | 商户后台未开启代付 |
| 403 | IP不在白名单中 | 请求IP不在商户配置的白名单 |
| 404 | 商户不存在 | 商户号错误 |
| 404 | 订单不存在 | 查询的订单号不存在 |
| 404 | 暂无可用通道 | 无匹配的收/付款产品 |
| 429 | 请求过于频繁,请稍后再试 | 超出API频率限制 |
| 500 | 服务器内部错误 | 平台异常,请联系客服 |
注意
商户对接时应优先判断
code(HTTP状态码),200 为成功,其他均为失败。message 为人类可读的错误描述,不建议作为程序判断依据(内容可能调整)。