3、回调
当订单处理完成后,系统会向商户配置的回调地址发送通知消息 。
回调地址配置
下单时可通过 notifyUrl 参数指定本次订单专属回调地址,该地址将覆盖商户后台配置的默认回调地址。
param.put("notifyUrl", "http://{域名}/callback/notifyUrl");
如果下单时未传入 notifyUrl,系统将回调商户后台配置的默认回调地址。
默认回调地址由商户创建时提供,并可在运营管理后台进行维护。
回 调请求方式
HTTP Method
POST
Content-Type
application/json
回调数据示例
{
"amount": "100",
"bizType": "WITHDRAW_ANY_DIGITAL_WALLET",
"blockchain": {
"network": "TRON",
"receiverAddress": "THcJ2FeNBkuzd4PZBpRans6tx9QGg9KHRt",
"senderAddress": "TE35TrUfHjbGEBsVS6zVXdHS8HxXCWwC2y",
"txIndex": "2",
"txId": "d848e4b62ec6925b8b3ff49dbc4d839f3f88508497c3af525f0c8293cb303ab3"
},
"currency": "CNY",
"localOrderId": "TestOTM0625ROB016",
"merchantActualAmount": "138.12",
"merchantCurrency": "CNY",
"merchantId": 302992856974,
"merchantPaidAmount": "100",
"notifyTime": 1772173006425,
"orderCreateTime": 1772172958082,
"orderId": "472515854147845",
"status": "SUCCESS",
"type": "WITHDRAW",
"userAmount": "14.971722",
"userCurrency": "USDT",
"userMinerFee": "0",
"isReissue": false,
"userReceivableAmount": "14.971722",
"rate": "6.71080951",
"rateExpression": "1USDT≈6.7108CNY",
"sign": "2c27c7e8184cc709a64ad502ee42eab7",
"key": "9yUreYgTRtit39Dy"
}
为满足业务发展需要,回调参数未来可能新增字段。新增字段默认参与签名计算(除签名规则中特别说明的 字段外),因此商户系统应具备向前兼容能力,避免因字段扩展导致验签失败。
回调参数说明
| 参数名称 | 类型 | 参与签名 | 参数含义 | 参数说明 |
|---|---|---|---|---|
| amount | decimal | 是 | 订单金额 | |
| bizType | enum | 是 | 订单类型 | 订单类型说明如下 |
| blockchain | object | 是 | 链交易信息 | 链上交易信息,仅当 isBlockchain=true 时返回 |
| └network | String | 是 | 主网 | |
| └receiverAddress | String | 是 | 接收地址 | |
| └senderAddress | decimal | 是 | 发送地址 | |
| └txId | String | 是 | 交易ID | 区块链交易哈希 |
| └txIndex | String | 是 | 交易索引 | 交易索引(批量转账场景) |
| currency | String | 是 | 币种 | 订单币种 |
| key | String | 是 | 商户 key | |
| localOrderId | String | 是 | 商户订单号 | |
| merchantActualAmount | decimal | 是 | 商户实际收付金额 | |
| merchantCurrency | String | 是 | 商户结算币种 | |
| merchantId | String | 是 | 商户号 | |
| merchantPaidAmount | decimal | 是 | 商户应收或应 付金额 | |
| merchantUserId | String | 是 | 商户用户 ID | |
| notifyTime | long | 是 | 回调时间 | 回调通知时间 |
| orderCreateTime | long | 是 | 订单创建时间 | |
| orderId | String | 是 | 订单号 | 平台订单号(唯一) |
| status | String | 是 | 支付状态 | SUCCESS 、 FAIL(说明如下) |
| type | String | 是 | 订单类型 | PAYMENT 、WITHDRAW(说明如下) |
| userAmount | decimal | 是 | 用户实收或实付金额 | |
| userCurrency | String | 是 | 用户币种 | |
| userMinerFee | String | 是 | 矿工费 | |
| userReceivableAmount | String | 是 | 用户应付或应收金额 | |
| isReissue | Boolean | 是 | 是否补发 | 是否补发回调 |
| rate | string | 是 | 汇率 | |
| rateExpression | string | 是 | 汇率表达式 | |
| sign | String | 否 | 签名值 | md5 签名(详情看签名算法) |
status 状态说明
| 状态值 | 说明 |
|---|---|
| SUCCESS | 已完成 |
| FAIL | 已失败 |
type 类型说明
| 类型值 | 说明 |
|---|---|
| PAYMENT | 支付 |
| WITHDRAW | 提款 |
bizType 业务类型说明
| bizType | 说明 |
|---|---|
| PAYMENT_WALLET_SCAN | VPAY 钱包扫码支付 |
| PAYMENT_TRANSFER | 数字货币绑定地址直充 |
| PAYMENT_ANY_DIGITAL_SCAN | 数字货币任意金额扫码支付 |
| PAYMENT_FIXED_DIGITAL_SCAN | 数字货币固定金额扫码支付 |
| WITHDRAW_WALLET | 提现至 VPAY 钱包 |
| WITHDRAW_ANY_DIGITAL_WALLET | 提现至任意数字钱包 |
| BATCH_PAY | 批量代付 |
回调响应要求
商户成功处理回调后,必须返回以下内容:
success
系统收到字符串 success 后,视为回调处理成功,不再重复发送。
回调重试机制
如果出现以下情况:
- 未收到响应
- 返回内容不是
success - HTTP 请求异常
- 服务超时
系统将自动重试发送回调通知。
最大重试次数
14次
重试间隔
15s
15s
30s
180s
600s
1200s
1800s
1800s
1800s
3600s
10800s
10800s
21600s
21600s
建议商户系统按照 orderId 实现幂等处理,避免因重复回调导致业务数据重复处理。
签名校验
收到回调通知后,商户必须先进行签名验证,验证通过后再执行业务逻辑。 签名算法与下单请求签名规则完全一致,请参考《2. 如何签名》。
验签流程
- 获取回调参数中的
sign - 从参数中移除
sign - 将商户
key放入参数 - 使用商户
secret按签名规则重新计算签名 - 比较计算结果与回调中的
sign是否一致
只有验签成功后,才应处理订单业务。
Java 验签示例
public void notify(JSONObject data) {
log.info("收到回调通知:{}", data.toJSONString());
String key = "your_key";
String secret = "your_secret";
String sign = data.getString("sign");
data.put("key", key);
data.remove("sign");
String calculatedSign = SignUtils.getSign(data, secret);
if (!calculatedSign.equals(sign)) {
throw new DxBizException("签名验证失败");
}
// 业务处理逻辑
}