三、回调
当下单成功后,会尝试发送消息通知发起方,在下单的时候指定 notifyUrl 参数覆盖默认回调地址
param.put("notifyUrl", "http://{域名}/callback/notifyUrl");
响应
响应 body 如下:
{
"amount": 100,
"bizType": "PAYMENT_FIXED_DIGITAL_SCAN",
"currency": "CNY",
"key": "h3cS7dBltRU4W1wD",
"localOrderId": "2820",
"merchantActualAmount": 8.86,
"merchantCurrency": "CNY",
"merchantId": 303122065665,
"merchantPaidAmount": 10.98,
"merchantUserId": "97",
"notifyTime": 1731572168370,
"orderCreateTime": 1731572133082,
"orderId": "273124814912907",
"sign": "699806308a9e055114c378671b0d2a15",
"status": "SUCCESS",
"type": "PAYMENT",
"userAmount": 1.55,
"userCurrency": "USDT"
}
回调参数说明:
参数名称 | 类型 | 参与签名 | 参数含义 | 参数说明 |
---|---|---|---|---|
amount | decimal | 是 | 订单金额 | |
bizType | enum | 是 | 订单类型 | bizType 类型说明如下 |
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 | 是 | 支付状态 | |
type | String | 是 | 订单类型 | PAYMENT:支付 WITHDRAW:提款 |
userAmount | decimal | 是 | 用户付款金额 | |
userCurrency | String | 是 | 用户支付币种 | |
sign | String | 否 | md5 签名 | 详情看签名算法 |
bizType 类型说明:
1、PAYMENT_WALLET_SCAN 点付钱包扫码支付
2、PAYMENT_TRANSFER 数字币绑定地址直充
3、PAYMENT_ANY_DIGITAL_SCAN 数字币任意金额扫码支付
4、WITHDRAW_WALLET 提款至点付钱包
5、WITHDRAW_ANY_DIGITAL_WALLET 提款数字币至任意钱包
6、PAYMENT_FIXED_DIGITAL_SCAN 数字币限定金额扫码支付
7、BATCH_PAY 批量代付
如果您接受到了回调信息,只需要返回success
,即表示消息已处理,本条回调不再会发送,否则会尝试重复发送直到获得期望的响应, 目前的重试频率为15s, 15s, 30s, 180s, 600s, 1200s, 1800s
,都无响应后,不再重复发送。
校验
服务器在发送回调消息时,会使用下单的 API 进行签名,接收方需验证签名后进行逻辑处理,,服务器的签名过程和下单发起签名的过程一致,接收方需要使用回调请求中的 body 进行加密,并校验回调的sign
是否一致
代码示例
public void notify(JSONObject data){
PaymentNotifyDto paymentNotifyDto = data.to(PaymentNotifyDto.class);
log.info("收到回调通知 {}", paymentNotifyDto);
String key = "key";
String secret = "secret";
//验证签名
String sign = data.getString("sign");
data.put("key", key);
data.remove("sign");
String validStr = SignUtils.getSign(data, secret);
if(!validStr.equals(sign)){
throw new DxBizException("签名错误");
}
}