# 回调交易结果

# 回调接口验签

验签目的

API 请求在通过公网传输过程中,有被中间人篡改的风险。为确保回调数据的完整性与可信性,平台支持并强烈建议商户在接收回调时进行签名验签

设置方式

登录【收银台后台】→【开发者中心】→【回调地址】→ 添加/编辑。

验签步骤

验签逻辑与接口请求签名大体一致,区别在于数据来源为接收到的回调内容

  1. 获取签名

从 HTTP 请求 Header 中读取签名字段:

sign: {平台生成的签名字符串}
  1. 获取回调参数体

将回调 Body 中的 JSON 参数以 key-value 形式存入一个 Map(字典)结构中。

  1. 添加公共参数

从 Header 中再取出以下字段,并一并加入 Map 中参与验签:

  • access_key
  • timestamp
  • nonce
  1. 构造待签名字符串

将 Map 中的所有 key 按照 ASCII 字典序从小到大排序,并拼接为如下格式的字符串:

plaintext

key1=value1&key2=value2&...&keyN=valueN
  1. 执行签名计算

使用商户后台绑定的 secret_key 对上述字符串进行以下处理:

  • 使用 HMAC_SHA1 算法加密
  • 将结果进行 Base64 编码,得到本地 sign
  1. 比对签名

将本地生成的 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 配置

支持两种通知地址配置方式:

  1. 【商户后台】配置统一回调地址
  • 可在「商户后台」→「开发者中心」中配置。
  • 适用于大部分订单共用的回调处理逻辑。

img

  1. 订单级别手动指定回调地址(notifyUrl)
  • 在创建订单接口中可传 notifyUrl 字段。
  • 若订单中指定了 notifyUrl 参数,则系统将仅使用该地址作为回调通知目标地址

地址优先级说明

订单中的 notifyUrl 优先级高于统一配置的回调地址。

响应状态码优先级说明

平台以 HTTP 响应状态码 (status_code) 是否为 200 作为通知是否成功的唯一判断标准

具体规则如下:

  • 只要商户系统返回 HTTP 200****,平台即认为回调成功
    • 此时即使返回内容不是 { "code": 200, "success": true } 也会被忽略。
  • ❌ 如果返回 status_code ≠ 200(如 400/500)或无响应,则判定为失败,平台将自动进行重试推送。