收款回调

收款订单成功完成后才会回调商户服务器,回调体固定为 status=completed。

系统仅推送收款、付款的最终结果,以 HTTP 2xx 作为成功标准并立即停止;首次失败后 1 分钟进行第 2 次投递,再失败则 5 分钟后进行第 3 次投递,总计最多 3 次。回调业务时间统一为北京时间 YYYY/MM/DD HH:mm:ss。

POST创建收款订单时请求体中的 notifyUrl

请求头

字段名称字段类型是否必填说明
content-typeapplication/json是固定为 application/json。
x-callback-timestampstring是回调发送时的毫秒时间戳。
x-callback-noncestring是回调随机串。
x-callback-signaturestring是HMAC-SHA256(apiKey, timestamp + "." + nonce + "." + rawBody)。
x-callback-signature-algorithmstring是固定为 HMAC-SHA256。
x-callback-signature-versionstring是固定为 v1。

接口参数

字段名称字段类型是否必填说明
merchantUidstring是Merchant UID。
orderNostring是平台订单号。
merchantOrderNostring | null是商户订单号。
bindKeystring | null是会员充值场景下的绑定键;共享收款订单通常为空。
chainCodestring | null是订单所属网络。
tokenSymbolstring | null是订单所属币种。
txHashstring | null是匹配的交易哈希,未检测到时为空。
expectedAmountstring | null是订单金额。
paidAmountstring是实际支付金额。
fromAddressstring | null是付款地址。
statusstring是收款成功终态,固定为 completed。
modestring是订单模式:shared 或 exclusive。
businessTypestring是订单业务类型。
serviceFeeUsdstring否本次收款服务费。
feeBalanceAfterUsdstring否扣费后的费用账户余额。
payerRiskStatusstring是付款来源风控状态。
payerRiskLabelstring | null是付款来源风控标签。

请求示例

{
  "merchantUid": "880001",
  "orderNo": "PI1776193200123ABCD1234",
  "merchantOrderNo": "M202604150001",
  "bindKey": null,
  "expectedAmount": "100.000000",
  "paidAmount": "100.000000",
  "chainCode": "TRON",
  "tokenSymbol": "USDT",
  "txHash": "f7f17891f52c35d0c93170f0d12bb347ac16ab34853b4bc8dcf7fd0a8c9aa321",
  "fromAddress": "TS7b7iD8G2PaPqK1TqSmLJ9nrrYH4oKX1S",
  "status": "completed",
  "mode": "shared",
  "businessType": "fixed",
  "serviceFeeUsd": "0.000000",
  "feeBalanceAfterUsd": "10.000000",
  "payerRiskStatus": "low_risk",
  "payerRiskLabel": "低风险"
}

接口返回

字段名称字段类型是否必填说明
HTTP Status200-299是任意 2xx 都视为成功。
Response Bodystring | json否内容可自定义。

返回示例

HTTP/1.1 200 OK
Content-Type: application/json

{
  "ok": true
}

代码示例

运行:Java 保存为 UUGateExample.java(回调为 UUGateCallback.java),使用 java 文件名;PHP 保存为 example.php,使用 php example.php;Go 保存为 example.go,使用 go run example.go;Node.js 保存为 example.mjs,使用 node example.mjs。回调原文从标准输入读取。

import { createHmac, timingSafeEqual } from 'node:crypto';

function required(name) {
  const value = process.env[name]?.trim();
  if (!value) throw new Error(name + ' is required');
  return value;
}
const key = required('UUGATE_API_KEY');
const timestamp = required('UUGATE_CALLBACK_TIMESTAMP'), nonce = required('UUGATE_CALLBACK_NONCE');
const signature = required('UUGATE_CALLBACK_SIGNATURE');
const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
const rawBody = Buffer.concat(chunks);
const expected = createHmac('sha256', key).update(timestamp + '.' + nonce + '.', 'utf8').update(rawBody).digest();
const actual = Buffer.from(signature, 'hex');
if (!/^[a-fA-F0-9]{64}$/.test(signature) || actual.length !== expected.length || !timingSafeEqual(expected, actual))
  throw new Error('Invalid callback signature');
console.log('VERIFIED');

说明

  • 回调验签使用 apiKey,而不是开放接口请求头里的 x-signature。
  • 验签后核对商户、订单、币种、网络和金额,在事务中按平台订单号幂等记录付款与业务结果,成功持久化后才返回 2xx;重复通知不得重复发货或入账。
  • 会员充值场景建议直接使用 bindKey 作为会员标识,不需要再额外维护 orderNo 到会员 ID 的映射表。
  • 以下代码只演示回调验签:将原始请求体作为标准输入,回调头映射到 UUGATE_CALLBACK_TIMESTAMP、UUGATE_CALLBACK_NONCE、UUGATE_CALLBACK_SIGNATURE,UUGATE_API_KEY 使用创建该订单时的 API Key。验签后仍须核对订单并事务幂等持久化,完成后才返回 HTTP 2xx。