# 回调交易结果
# 回调接口验签
验签目的
API 请求在通过公网传输过程中,有被中间人篡改的风险。为确保回调数据的完整性与可信性,平台支持并强烈建议商户在接收回调时进行签名验签。
设置方式
登录【收银台后台】→【开发者中心】→【回调地址】→ 添加/编辑。
验签步骤
验签逻辑与接口请求签名大体一致,区别在于数据来源为接收到的回调内容。
- 获取签名
从 HTTP 请求 Header 中读取签名字段:
sign: {平台生成的签名字符串}
- 获取回调参数体
将回调 Body 中的 JSON 参数以 key-value 形式存入一个 Map(字典)结构中。
- 添加公共参数
从 Header 中再取出以下字段,并一并加入 Map 中参与验签:
access_key
timestamp
nonce
- 构造待签名字符串
将 Map 中的所有 key 按照 ASCII 字典序从小到大排序,并拼接为如下格式的字符串:
plaintext
key1=value1&key2=value2&...&keyN=valueN
- 执行签名计算
使用商户后台绑定的 secret_key
对上述字符串进行以下处理:
- 使用
HMAC_SHA1
算法加密 - 将结果进行
Base64
编码,得到本地sign
值
- 比对签名
将本地生成的 sign
与 Header 中平台传来的 sign
进行比对:
- ✅ 一致 → 验签通过,可处理业务逻辑
- ❌ 不一致 → 拒绝处理,建议记录日志以供排查
# 收款回调
接口说明
当用户通过链上完成支付后,平台将根据订单状态自动向商户系统发送回调请求(HTTP POST)。回调信息中包含支付状态、金额、链上交易哈希等关键字段。
回调数据格式(JSON)
{
"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"
}
回调字段说明
参数名 | 类型 | 描述 |
---|---|---|
orderActualAmount | String | 实际支付金额(代币金额) |
orderAmount | String | 原始订单金额(代币金额) |
orderFee | String | 手续费 |
orderId | String | 平台订单号 |
externalOrderId | String | 商户订单号 |
orderTime | int64 | 订单创建时间(毫秒时间戳) |
orderPayTime | int64 | 订单完成时间 |
currencyType | String | 法币类型,如:USD、BRL |
exchangeRate | String | 创建订单时法币兑换率 |
chainType | String | 主链类型,如 ETH / TRON / BSC |
tokenType | String | 代币类型,如 USDT / USDC / DAI |
addressTo | String | 收款地址(平台收款地址) |
addressFrom | String | 用户付款地址(链上转出地址) |
tradeHash | String | 区块链交易哈希,可用于链上查询交易状态 |
orderStatusCode | int64 | 状态码,枚举值:1、2、4、8、16 详细说明请参考下方订单状态码说明 |
orderStatus | int64 | 订单状态码描述 |
订单状态码说明
状态码 | 状态描述 | 是否终态 | 说明 |
---|---|---|---|
1 | 待支付 | 否 | 订单已创建,用户尚未付款;无需处理 |
2 | 链上确认中 | 否 | 用户在收银台点击“已完成支付”,系统正在检测链上是否到账;无需处理 |
4 | 已完成 | 是 | 支付成功,系统会触发回调;商户需根据业务逻辑增加余额或完成发货等操作 |
8 | 支付金额不匹配 | 是 | 用户支付金额 ≠ 应付金额,系统会触发回调;建议按实际支付金额入账 |
16 | 超时收款 | 是 | 用户支付超时,系统不会再回调;商户如确认收款到账需手动处理 |
32 | 未支付(地址释放) | 是 | 用户长时间未支付,地址释放;若后续支付将生成新订单 |
📌 手动回调说明(商户后台操作)
商户可在任意时间登录商户后台,针对特定订单手动发起回调通知。
使用方式
- 登录商户后台 → 订单管理 → 操作;
- 点击【手动回调】,平台将立即向该订单的
notifyUrl
发起回调。
⚠️ 注意事项
- 建议仅对已进入“终态”的订单进行手动回调:
- 即
orderStatusCode
=4
(已完成)、8
(金额不符)、16
(超时)等;
- 即
- 不建议对非终态订单执行回调(如状态为
1
待支付、2
确认中);- 因为订单后续仍可能进入终态,平台在状态变化后仍会自动再次触发回调;
- 若商户重复处理未完成订单,可能导致入账错误或数据冗余;
💡 商户建议
- 请务必在回调接收端实现幂等处理逻辑(同一订单回调多次仅处理一次);
- 对于异常未接收的回调,建议先检查签名、Header 参数、网络连通等情况,再选择手动触发。
# 代付回调
接口说明
当商户发起的链上代付订单状态更新(如代付成功、失败、拒绝等)后,平台会主动向商户配置的 notifyUrl
发送回调通知。
回调数据格式(JSON)
{
"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"
}
回调字段说明
参数名 | 类型 | 描述 |
---|---|---|
orderId | String | 平台订单 ID |
externalOrderId | String | 商户订单 ID |
orderAmount | String | 原始代付金额(代币单位) |
orderFee | String | 手续费金额(平台收取) |
orderTime | int64 | 订单创建时间(毫秒时间戳) |
orderPayTime | int64 | 实际完成时间 |
chainType | String | 主链类型,如:ETH、TRON、BSC |
tokenType | String | 加密币种,如:USDT、USDC、DAI |
tradeHash | String | 区块链交易哈希,可链上查询交易状态 |
addressTo | String | 用户收款地址 |
orderStatus | String | 订单状态描述,如:Completed |
orderStatusCode | int64 | 订单状态码,见下方状态码定义 |
orderStatusCode
状态码定义
状态码 | 描述 | 是否终态 | 说明 |
---|---|---|---|
1 | 已受理 | 否 | 平台已接收代付请求,尚未上链处理 |
2 | 已完成 | 是 | 出款成功,交易已上链 |
4 | 出款失败 | 是 | 出款失败(如手续费不足/链异常) |
8 | 待审批 | 否 | 风控限制或权限配置下需人工审核 |
16 | 拒绝出款 | 是 | 审核不通过,订单终止 |
回调响应
说明
- 所有回调均包含签名字段,建议商户务必对回调进行验签,确保回调内容未被篡改。
- 商户在收到回调数据并处理完成后,需以 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 | ✅ | 响应是否成功 |
# 回调通知 URL 配置
支持两种通知地址配置方式:
- 【商户后台】配置统一回调地址
- 可在「商户后台」→「开发者中心」中配置。
- 适用于大部分订单共用的回调处理逻辑。
- 订单级别手动指定回调地址(notifyUrl)
- 在创建订单接口中可传
notifyUrl
字段。 - 若订单中指定了
notifyUrl
参数,则系统将仅使用该地址作为回调通知目标地址。
地址优先级说明
订单中的 notifyUrl
优先级高于统一配置的回调地址。
响应状态码优先级说明
平台以 HTTP 响应状态码 (status_code
) 是否为 200
作为通知是否成功的唯一判断标准。
具体规则如下:
- ✅ 只要商户系统返回
HTTP 200
****,平台即认为回调成功- 此时即使返回内容不是
{ "code": 200, "success": true }
也会被忽略。
- 此时即使返回内容不是
- ❌ 如果返回
status_code ≠ 200
(如 400/500)或无响应,则判定为失败,平台将自动进行重试推送。