# 回调交易结果
# 回调接口验签
验签目的
API 请求在通过公网传输过程中,有被中间人篡改的风险。为确保回调数据的完整性与可信性,平台支持并强烈建议商户在接收回调时进行签名验签。
设置方式
登录【收银台后台】→【开发者中心】→【回调地址】→ 添加/编辑。
验签步骤
验签逻辑与接口请求签名大体一致,区别在于数据来源为接收到的回调内容。
- 获取签名
从 HTTP 请求 Header 中读取签名字段:
sign: {平台生成的签名字符串}
- 获取回调参数体
将回调 Body 中的 JSON 参数以 key-value 形式存入一个 Map(字典)结构中。
- 添加公共参数
从 Header 中再取出以下字段,并一并加入 Map 中参与验签:
access_key
timestamp
nonce
- 构造待签名字符串
将 Map 中的所有 key 按照 ASCII 字典序从小到大排序,并拼接为如下格式的字符串:
key1=value1&key2=value2&...&keyN=valueN
- 执行签名计算
使用商户后台绑定的 secret_key
对上述字符串进行以下处理:
- 使用
HMAC_SHA1
算法加密 - 将结果进行
Base64
编码,得到本地sign
值
- 比对签名
将本地生成的 sign
与 Header 中平台传来的 sign
进行比对:
- ✅ 一致 → 验签通过,可处理业务逻辑
- ❌ 不一致 → 拒绝处理,建议记录日志以供排查
# 收款回调
回调数据示例
{
"currencyType": "USD",
"orderActualAmount": "1",
"orderId": "OCRYPPAID202307310902391690794159441DOCKER020000000400001108",
"tradeHash": "0x806d5b3da29c8426a644e2ded85b865b37504dcdec4cfb9db13af5e962815528",
"orderFee": "1",
"orderStatus": "Completed",
"chainType": "ETH",
"externalOrderId": "402297358314559082",
"addressTo": "0xe072c63c1e04f8c6f36133f6629f66778147d5d8",
"orderAmount": "1",
"orderTime": 1690794159000,
"exchangeRate": "0.983",
"orderStatusCode": 4,
"orderPayTime": 1690794247000,
"addressFrom": "0x0cbfd17ae9e1d6d881b2cade71277f48abf64d24",
"tokenType": "USDT"
}
回调字段说明
参数名 | 类型 | 描述 |
---|---|---|
currencyType | String | 法币类型(如 USD) |
orderActualAmount | String | 实际支付金额 |
orderId | String | 平台订单ID |
tradeHash | String | 区块链交易哈希 |
orderFee | String | 手续费金额 |
orderStatus | String | 订单状态文本(如 Completed) |
orderStatusCode | int64 | 订单状态码(见下方说明) |
chainType | String | 区块链主链类型(如 ETH) |
externalOrderId | String | 商户订单号 |
addressTo | String | 收款地址 |
addressFrom | String | 出款地址 |
orderAmount | String | 原始订单金额 |
orderTime | int64 | 订单创建时间(Unix 毫秒) |
orderPayTime | int64 | 实际支付时间(Unix 毫秒) |
exchangeRate | String | 汇率 |
tokenType | String | 加密代币类型(如 USDT) |
markStatus | String | 标记状态(如需支持) |
errorMsg | String | 错误信息(中文) |
errorMsgEn | String | 错误信息(英文) |
订单状态码说明(orderStatusCode)
状态码 | 描述 |
---|---|
1 | 待支付:订单创建成功,等待用户付款 |
2 | 链上确认中:用户点击“我已付款”,等待链上确认 |
4 | 已完成:支付成功,平台会自动发送回调通知 |
8 | 支付金额不匹配:仍回调通知,请根据实际金额入账 |
16 | 超时收款:用户未按时支付,不再回调通知 |
32 | 未支付:地址过期回收,不再处理 |
⚠️ 回调处理建议
- 回调一旦验签通过且
orderStatusCode == 4
,即可视为支付成功,应立即执行上分 / 业务处理。 - 平台可能因网络等原因重复推送回调,请务必做好幂等处理,避免重复入账。
- 若验签失败或数据异常,请记录日志并返回错误响应,平台将在最多 30 分钟内自动重试 2 次。
手动回调说明
商户可在后台订单管理中手动触发回调,用于修复漏回调情况。但请注意:
- 若订单状态非终态(如:待支付、确认中),不建议手动回调。
- 若手动回调时订单尚未完成,平台在状态变为终态后仍会再次回调,请商户做好业务层面的去重处理。
# 代付回调
回调数据示例
{
"orderAmount": "1",
"orderTime": 1690794160000,
"orderId": "OCRYPDRAW202307310902401690794160841DOCKER020000000200001109",
"orderStatusCode": 2,
"tradeHash": "0xe9d043c9cbdb96ed7a71c5a0923baabe9e23316b3f1b0a01975bcd6d69b41fa3",
"orderFee": "0.01",
"orderStatus": "Completed",
"orderPayTime": 1690794182000,
"chainType": "ETH",
"externalOrderId": "622257420681202921",
"tokenType": "USDT",
"addressTo": "0xa8666442fA7583F783a169CC9F5449ec660295E8"
}
回调字段说明
参数名 | 类型 | 描述 |
---|---|---|
orderAmount | String | 订单金额 |
orderTime | int64 | 订单创建时间(Unix 毫秒) |
orderId | String | 平台订单ID |
orderStatusCode | int64 | 订单状态码(见下方说明) |
tradeHash | String | 区块链交易哈希 |
orderFee | String | 手续费金额 |
orderStatus | String | 订单状态描述(如 Completed) |
orderPayTime | int64 | 出款完成时间(Unix 毫秒) |
chainType | String | 区块链主链类型(如 ETH) |
externalOrderId | String | 商户订单号 |
tokenType | String | 加密代币类型(如 USDT) |
addressTo | String | 收款地址 |
订单状态码说明(orderStatusCode)
状态码 | 描述 |
---|---|
1 | 已受理 |
2 | 已完成(出款成功) |
4 | 出款失败 |
8 | 待审批 |
16 | 拒绝出款 |
⚠️ 回调处理建议
- 当
orderStatusCode == 2
且验签通过,即可确认出款成功,请执行上分 / 发货 / 状态更新等操作。 - 回调推送支持多次重发,请务必支持幂等性处理。
- 若返回非 200 响应或验签失败,平台将尝试再次回调。
手动回调说明
商户可登录后台进行手动触发回调操作。请注意以下事项:
- 不建议对“非终态订单”发起手动回调,如:状态为“已受理”、“待审批”等;
- 若手动回调的订单仍处于非终态,未来状态变更为终态时平台仍将再次回调,商户需做好业务层面的冗余处理;
# 回调响应
说明
- 所有回调均包含签名字段,建议商户务必对回调进行验签,确保回调内容未被篡改。
- 商户在收到回调数据并处理完成后,需以 JSON格式 响应网关如下数据:
示例响应(成功)
{
"code": 200,
"success": true
}
回调补发机制说明(重要)🔥
为确保回调通知的稳定送达与业务一致性,平台设计了多次重试策略。当商户系统未能成功响应回调时(如网络超时、返回非200状态码等),系统将按以下规则进行回调补发:
回调重试节奏(共 4 次):
尝试次数 | 间隔时间(约) | 说明 |
---|---|---|
第 1 次 | 约 2 分钟后 | 首次失败后触发第一次重试 |
第 2 次 | 约 2 分钟后 | 第一次充实失败后触发第二次重试 |
第 3 次 | 再约 11分钟后 | 第二次重试失败后再次重试 |
第 4 次 | 再约 2分钟后 | 第三次重试失败后进入下一次重试 |
注意:以上间隔时间为系统内部调度间隔,商户后台所记录的“回调时间”包含了商户处理/响应时间,因此显示上可能与实际推送时间存在 1 分钟左右误差。
实际情况提醒
- 当线上订单量较大时,回调可能存在队列延迟,请确保服务端支持高并发处理能力;
- 每次回调均为幂等操作,建议商户侧务必支持幂等判断;
- 最多 4 次重试推送仍失败后,则不再自动重试,建议通过后台手动触发回调。
回调响应参数
Param | Type | Required | Description |
---|---|---|---|
code | int | ✅ | 状态码,成功为 200 |
success | boolean | ✅ | 响应是否成功 |
回调响应要求
商户服务需返回如下标准响应:
{
"code": 200,
"success": true
}
响应类型
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
⚠️ 特别说明
- 平台只判断 HTTP Status Code 是否为
200
,只要状态码为200
,即视为回调成功,不再校验响应内容。 - 若返回非
200
状态(如500
/404
),则会视为失败并触发重试机制。
商户建议实践
- 验签成功且业务处理完成后立即返回
200
。 - 若处理失败,记录日志并确保平台后续补发能正常接收。
- 建议使用异步任务处理回调内容,避免阻塞响应。
# 回调通知 URL 配置
支持两种通知地址配置方式:
- 【商户后台】配置统一回调地址
- 可在「商户后台」→「开发者中心」中配置。
- 适用于大部分订单共用的回调处理逻辑。
2.订单级别手动指定回调地址(notifyUrl)
- 在创建订单接口中可传
notifyUrl
字段。 - 若订单中指定了
notifyUrl
参数,则系统将仅使用该地址作为回调通知目标地址。
地址优先级说明
订单中的 notifyUrl
优先级高于统一配置的回调地址。
响应状态码优先级说明
平台以 HTTP 响应状态码 (status_code
) 是否为 200
作为通知是否成功的唯一判断标准。
具体规则如下:
- ✅ 只要商户系统返回
HTTP 200
****,平台即认为回调成功- 此时即使返回内容不是
{ "code": 200, "success": true }
也会被忽略。
- 此时即使返回内容不是
- ❌ 如果返回
status_code ≠ 200
(如 400/500)或无响应,则判定为失败,平台将自动进行重试推送。