重发回调通知接口
接口说明
重发异步回调通知接口,支持通过平台订单号(transactionNo)或商户订单号(orderNo)重新发送支付成功的异步回调消息给商户。
适用对象
间连商户
请求 URL
https://openapi.shuhuipay.com/v1/order/notify请求方法
POST
使用场景:
- 商户未收到异步通知或通知处理失败,需要重发
- 商户主动请求重发通知以更新订单状态
- 仅对支付成功(status=2)的订单有效
频率限制:
- 每个商户每分钟最多调用 60 次,超过限制将返回错误码 9000
- 建议商户端做好请求频率控制,避免频繁调用
请求参数(bizContent)
transactionNo、orderNo 二者必须提供其中一个。推荐使用 transactionNo(平台订单号)进行查询,效率更高。
| 参数名 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
transactionNo |
String | 二选一 | 平台订单号,与 orderNo 二选一 |
orderNo |
String | 二选一 | 商户订单号,与 transactionNo 二选一 |
请求示例
通过 transactionNo 查询(推荐)
JSON
{
"appId": "you_system_appid",
"subMerchantNo": "your_user_id",
"bizContent": "{\"transactionNo\":\"SHPAY_202607021507077387091\"}",
"version": "1.0",
"nonce": "49d55020fa3adf6ed67b253c583ccdaa",
"contentHash": "95772c8a0c74e52b707e2ace5963e0eae956e8b1ae26e86a6cde5469247d0382",
"timestamp": "2026-07-10 14:33:11",
"sign": "your_sign"
}
通过 orderNo 查询
JSON
{
"appId": "you_system_appid",
"subMerchantNo": "your_user_id",
"bizContent": "{\"orderNo\":\"TEST202607021506596406\"}",
"version": "1.0",
"nonce": "49d55020fa3adf6ed67b253c583ccdaa",
"contentHash": "95772c8a0c74e52b707e2ace5963e0eae956e8b1ae26e86a6cde5469247d0382",
"timestamp": "2026-07-10 14:33:11",
"sign": "your_sign"
}
响应参数
公共返回参数
| 参数 | 类型 | 必须 | 参数说明 |
|---|---|---|---|
code |
String | Y | 响应状态码,成功 0000 |
message |
String | Y | 响应描述 |
timestamp |
String | Y | 响应时间戳,UTC 时间,ISO 8601 格式 |
data |
Object | Y | 业务数据,无数据时返回空对象 {} |
响应附加参数(data)
| 参数名 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
transactionNo |
String | Y | 平台订单号 |
orderNo |
String | Y | 商户订单号 |
notifyStatus |
Integer | Y | 通知状态,1 表示通知发送成功 |
错误码说明
| 错误码 | 说明 |
|---|---|
0000 |
成功 |
4001 |
参数错误(transactionNo 和 orderNo 同时为空) |
4000 |
业务错误(订单未支付、未配置通知地址等) |
4004 |
订单不存在 |
5000 |
系统异常或通知发送失败 |
响应示例
成功响应:
JSON
{
"code": "0000",
"message": "通知发送成功",
"timestamp": "2026-07-10T10:30:00.000Z",
"data": {
"transactionNo": "SHPAY_202607021507077387091",
"orderNo": "TEST202607021506596406",
"notifyStatus": 1
}
}
失败响应:
JSON
// 订单未支付,无法发送通知
{
"code": "4000",
"message": "订单未支付,无法发送通知",
"timestamp": "2026-07-10T10:30:00.000Z",
"data": {}
}
// 参数缺失
{
"code": "4001",
"message": "transactionNo 和 orderNo 不能同时为空",
"timestamp": "2026-07-10T10:30:00.000Z",
"data": {}
}
// 订单不存在
{
"code": "4004",
"message": "订单号 ORDER202501150001 不存在或不属于当前商户",
"timestamp": "2026-07-10T10:30:00.000Z",
"data": {}
}
代码示例
Java
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
public class ReplayNotifyExample {
public static void main(String[] args) {
// 方式一:通过平台订单号重发通知
Map<String, String> notifyByTransactionNo = new HashMap<>();
notifyByTransactionNo.put("transactionNo", "SHPAY_202607021507077387091");
String result1 = replayNotify(notifyByTransactionNo);
System.out.println("重发结果:" + result1);
// 方式二:通过商户订单号重发通知
Map<String, String> notifyByOrderNo = new HashMap<>();
notifyByOrderNo.put("orderNo", "TEST202607021506596406");
String result2 = replayNotify(notifyByOrderNo);
System.out.println("重发结果:" + result2);
}
public static String replayNotify(Map<String, String> queryParams) {
String appId = "your_app_id";
String subMerchantNo = "your_user_id";
String signKey = "your_sign_key";
String apiUrl = "https://openapi.shuhuipay.com/v1/order/notify";
Map<String, String> requestData = new HashMap<>();
requestData.put("appId", appId);
requestData.put("subMerchantNo", subMerchantNo);
requestData.put("bizContent", JSON.toJSONString(queryParams));
requestData.put("version", "1.0");
requestData.put("nonce", "49d55020fa3adf6ed67b253c583ccdaa");
requestData.put("contentHash", "95772c8a0c74e52b707e2ace5963e0eae956e8b1ae26e86a6cde5469247d0382");
requestData.put("timestamp", "2026-07-10 14:33:11");
String sign = SignUtil.generateSign(requestData, signKey);
requestData.put("sign", sign);
String response = HttpUtil.post(apiUrl, requestData);
return response;
}
}
Python
import requests
import json
import hashlib
def replay_notify(query_params):
"""重发异步回调通知"""
sys_appid = "your_sys_appid"
open_subMerchantNo = "your_open_subMerchantNo"
sign_key = "your_sign_key"
api_url = "https://openapi.shuhuipay.com/v1/order/notify"
request_data = {
"sys_appid": sys_appid,
"open_subMerchantNo": open_subMerchantNo,
"version": "1.0",
"timestamp": "2026-07-10 14:33:11",
"replay": "49d55020fa3adf6ed67b253c583ccdaa",
"bizContent": json.dumps(query_params),
"data_hash": "95772c8a0c74e52b707e2ace5963e0eae956e8b1ae26e86a6cde5469247d0382",
}
sign = generate_sign(request_data, sign_key)
request_data["sign"] = sign
try:
response = requests.post(api_url, json=request_data, timeout=30)
return response.json()
except Exception as e:
print(f"重发通知失败: {e}")
return None
def generate_sign(params, sign_key):
sorted_params = sorted(params.items())
sign_str = "&".join([f"{k}={v}" for k, v in sorted_params if v])
sign_str += f"&key={sign_key}"
return hashlib.md5(sign_str.encode()).hexdigest().upper()
# 方式一:通过平台订单号重发通知
result1 = replay_notify({"transactionNo": "SHPAY_202607021507077387091"})
# 方式二:通过商户订单号重发通知
result2 = replay_notify({"orderNo": "TEST202607021506596406"})
# 处理返回结果
if result1 and result1.get("code") == "0000":
data = result1.get("data", {})
print("通知发送成功")
print(f"平台订单号: {data.get('transactionNo')}")
print(f"商户订单号: {data.get('orderNo')}")
else:
print(f"通知发送失败: {result1.get('message')}")
PHP
<?php
class ReplayNotify {
private $appId = 'your_app_id';
private $subMerchantNo = 'your_user_id';
private $signKey = 'your_sign_key';
private $apiUrl = 'https://openapi.shuhuipay.com/v1/order/notify';
public function replayNotify($queryParams) {
$requestData = [
'appId' => $this->appId,
'subMerchantNo' => $this->subMerchantNo,
'bizContent' => json_encode($queryParams),
'version' => '1.0',
'nonce' => '49d55020fa3adf6ed67b253c583ccdaa',
'contentHash' => '95772c8a0c74e52b707e2ace5963e0eae956e8b1ae26e86a6cde5469247d0382',
'timestamp' => '2026-07-10 14:33:11',
];
$requestData['sign'] = $this->generateSign($requestData);
$response = $this->httpPost($this->apiUrl, $requestData);
return json_decode($response, true);
}
private function generateSign($params) {
ksort($params);
$signStr = '';
foreach ($params as $key => $value) {
if ($value !== '') {
$signStr .= "{$key}={$value}&";
}
}
$signStr .= "key={$this->signKey}";
return strtoupper(md5($signStr));
}
private function httpPost($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
// 方式一:通过平台订单号重发通知
$result1 = (new ReplayNotify())->replayNotify([
'transactionNo' => 'SHPAY_202607021507077387091'
]);
// 方式二:通过商户订单号重发通知
$result2 = (new ReplayNotify())->replayNotify([
'orderNo' => 'TEST202607021506596406'
]);
// 处理返回结果
if ($result1 && $result1['code'] === '0000') {
$data = $result1['data'] ?? [];
echo "通知发送成功\n";
echo "平台订单号: " . ($data['transactionNo'] ?? '') . "\n";
echo "商户订单号: " . ($data['orderNo'] ?? '') . "\n";
} else {
echo "通知发送失败: " . ($result1['message'] ?? '未知错误') . "\n";
}
注意事项
调用限制:
- 仅对支付成功(status=2)的订单有效,其他状态会返回错误码 4000
- 订单必须配置了
notify_url,否则无法发送通知 - 每个商户每分钟最多调用 60 次,超过限制将返回错误码 9000
使用建议:
- 推荐使用
transactionNo(平台订单号)进行调用,效率更高 - 通知会重新签名并发送到订单的
notify_url - 发送结果会记录到通知日志表,可通过管理后台查看
最佳实践:
- 仅在商户确认未收到通知或通知处理失败时调用此接口
- 调用后请检查返回的
notifyStatus字段确认通知是否发送成功 - 建议在调用前先使用订单查询接口确认订单状态