异步回调
接口说明
异步通知回调接口是数汇科技支付系统在订单支付成功后,主动向商户服务器发送的支付结果通知。商户通过该接口可以实时获取订单支付状态,确保业务处理的及时性和准确性。
重要说明:异步通知是确保支付结果准确性的重要机制,商户必须正确处理该回调接口。
通知参数
数汇科技系统会以 POST 方式向商户在下单时提供的 notify_url 地址发送支付结果通知。
| 参数 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
| appId | String | Y | 请求接口时使用的平台应用ID |
| userId | String | Y | 用户账户编号 |
| orderNo | String | Y | 商户订单编号 |
| transactionNo | String | Y | 系统订单编号(系统流水号) |
| amount | String | Y | 订单金额(元),保留两位小数 |
| sign | String | Y | 签名(签名方式同下单时一致) |
通知示例
{
"appId": "your_app_id",
"userId": "your_user_id",
"orderNo": "ORDER20260701001",
"transactionNo": "SHPAY202607011030001234567890",
"amount": "100.00",
"sign": "sign_value"
}
返回要求
重要要求:收到通知后需要返回大写 SUCCESS
商户服务器收到异步通知后,必须返回字符串: SUCCESS(大写),表示已成功接收通知。
| 返回示例 | 是否正确 | 说明 |
|---|---|---|
| SUCCESS | ✓ 正确 | 正确返回,大写 |
| success | ✗ 错误 | 错误:小写 |
| OK | ✗ 错误 | 错误:错误字符串 |
| {"code": "success"} | ✗ 错误 | 错误:JSON格式 |
重试机制
重试规则:如未返回 SUCCESS,系统将按以下频率进行回调,最多回调15次。
| 回调次数 | 重试间隔 | 说明 |
|---|---|---|
| 首次回调失败后 | 5秒 | 快速重试 |
| 第二次 | 30秒 | 短期重试 |
| 第三次 | 60秒 | 中期重试 |
| 第四次 | 10分钟 | 长期重试开始 |
| 第五次及后续 | 1小时 | 定期重试直到15次 |
签名验证
收到回调参数后,需要验证签名以确保请求来源的合法性。签名方式与下单时保持一致(RSA2 / SM2)。
本页为通用介绍,仅作示例参考。各签名方式的完整实现请查看「签名与加密」页面。
RSA2 验签示例
<?php
// 异步回调处理示例
public function notify()
{
// 获取回调参数
$param = [
'appId' => $_POST['appId'],
'userId' => $_POST['userId'],
'orderNo' => $_POST['orderNo'],
'transactionNo' => $_POST['transactionNo'],
'amount' => $_POST['amount'],
];
// 对参数进行排序
ksort($param);
// 验证签名(RSA2)
$sign = $_POST['sign'];
$verifyResult = $this->rsaVerify($param, $sign, $publicKey);
if ($verifyResult && !empty($sign)) {
// 签名验证成功,处理业务逻辑
$orderNo = $_POST['orderNo'];
$transactionNo = $_POST['transactionNo'];
// TODO: 更新订单状态、记录支付信息等业务处理
// 返回成功标识(必须大写)
return 'SUCCESS';
} else {
// 签名验证失败
return 'sign fail';
}
}
// RSA2 验签方法
private function rsaVerify($data, $sign, $publicKey)
{
ksort($data);
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($publicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$pubkeyid = openssl_pkey_get_public($res);
return openssl_verify($json, base64_decode($sign), $pubkeyid, OPENSSL_ALGO_SHA256) === 1;
}
SM2 验签流程
依赖说明:PHP 示例使用封装好的
Sm2Helper 类,基于 lpilp/guomi: ^2.0 库实现。其他语言请参考以下逻辑自行实现。
验签步骤说明:
| 步骤 | 操作 | 详细说明 |
|---|---|---|
| 1 | 获取回调数据 | 从请求 Body 中获取原始数据(支持 JSON 或 URL 编码格式) |
| 2 | 解析参数 | 根据数据格式解析为关联数组/对象,包含 userId、orderNo、sign 等字段 |
| 3 | 提取并移除 sign | 保存 sign 参数值,然后从参数中移除 sign 字段 |
| 4 | 构建验签字符串 | 将剩余参数转为 JSON 字符串(不转义中文、不转义斜杠) |
| 5 | SM2 验证签名 | 使用平台 SM2 公钥对 JSON 字符串和 sign 进行验签 |
| 6 | 处理业务逻辑 | 验签成功后更新订单状态,返回 SUCCESS |
关键点说明:
- 数据格式:回调数据可能是 JSON 或 URL 编码格式,需兼容处理
- 参数排序:验签前无需对参数进行排序,保持原始顺序即可
- 移除 sign:验签前必须先移除 sign 参数,再将剩余参数转为 JSON
- JSON 编码:使用不转义的 JSON 编码(保留中文、不转义斜杠)
- SM2 验签:使用平台提供的 SM2 公钥验证签名
PHP 示例代码:
<?php
// SM2 异步回调处理示例
try {
// 获取POST数据(支持JSON和URL编码格式)
$postData = file_get_contents('php://input');
if (empty($postData)) {
$postData = http_build_query($_POST);
}
// 解析通知参数
$params = [];
if (strpos($postData, '{') === 0) {
// JSON格式
$params = json_decode($postData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('JSON解析失败: ' . json_last_error_msg());
}
} else {
// URL编码格式
parse_str($postData, $params);
}
if (empty($params)) {
throw new Exception('通知参数为空');
}
// 验证必要参数
$requiredFields = ['appId', 'userId', 'orderNo', 'transactionNo', 'amount', 'sign'];
foreach ($requiredFields as $field) {
if (!isset($params[$field]) || $params[$field] === '') {
throw new Exception("缺少必要参数: {$field}");
}
}
// 提取签名并移除sign参数
$receivedSign = $params['sign'];
unset($params['sign']);
// 构建验签数据(与平台签名时的格式保持一致)
$signData = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// 使用平台SM2公钥验证签名
$platformSm2PublicKey = 'your_platform_sm2_public_key';
$verifyResult = Sm2Helper::verify($signData, $receivedSign, $platformSm2PublicKey);
if (!$verifyResult) {
throw new Exception('签名验证失败');
}
// 签名验证成功,处理业务逻辑
$orderNo = $params['orderNo'];
$transactionNo = $params['transactionNo'];
$amount = $params['amount'];
// TODO: 更新订单状态、记录支付信息等业务处理
// 返回成功标识(必须大写)
echo 'SUCCESS';
} catch (Exception $e) {
// 异常处理
error_log('SM2回调异常: ' . $e->getMessage());
echo 'FAIL';
}