AinePay
EN中文
Webhooks

支付通知

当订单最终状态确定时,AinePay 会给商户系统推送订单状态变化的通知以方便商户端及时处理。

端点

  • 方法: POST
  • 目标 URL: {notifyUrl}/ainepay/notify
  • 认证: 需要签名验证(含时间窗校验)
  • Content-Type: application/x-www-form-urlencoded
  • 请求头:
    • x-api-signature:HMAC-SHA256 十六进制小写
    • x-api-timestamp:毫秒级时间戳,参与签名
    • x-api-recv-window:接收窗口(毫秒),参与签名

投递行为

  • Webhook 在订单状态发生需要通知商户的变化时创建。
  • 在当前实现中,AinePay 为 PAIDEXPIREDCANCELREFUND 发送通知。
  • 通过支付链接(PAYMENT_LINK)创建的订单不发送回调。
  • AinePay 将任何 HTTP 2xx 响应视为成功确认(不跟随重定向)。
  • 如果端点返回非 2xx 状态或请求失败,AinePay 会以指数退避方式重试:基础延迟 5 秒,第 n 次重试延迟为 5 秒 × 2^(n-1),最多尝试 5 次,之后不再重试。
  • 当商户被限流时,本次投递以 30 秒退避重新调度。

请求字段

字段类型描述是否必需示例
merchantIdstring商户 ID。20001
orderIdstring商户订单 ID。ORDER_10001
userIdstring商户定义的用户 ID。U_90001
coinstring代币符号。USDT
chainstring链代码。ETH
qtystring订单金额,格式化字符串。88.00
statusstring(enum)订单状态。在当前实现中,Webhook 状态为 PAIDEXPIREDCANCELREFUNDPAID
expiredinteger订单过期时间戳(毫秒)。1760000600000
createdinteger订单创建时间戳(毫秒)。1760000000000
updatedinteger订单最后更新时间戳(毫秒)。1760000300000

签名验证

  • AinePay 使用商户的 Webhook 验证密钥签署「URL 编码的 Webhook 正文 + &timestamp=<ts>&recvWindow=<rw>」。
  • 签名在 x-api-signature 中以小写十六进制发送;时间戳与窗口分别在 x-api-timestampx-api-recv-window 中发送,并参与 HMAC 计算。
  • 签名输入的 body 段是按字段名排序的规范 URL 编码表单字符串;末尾的 timestamp/recvWindow 为纯数字,再做 URL 编码。
  • 商户验证步骤:
    1. 读取 x-api-timestampx-api-recv-window,校验 |now - timestamp| ≤ min(recvWindow, MAX_ACCEPTABLE_RECV_WINDOW),超出窗口直接拒绝(推荐 MAX_ACCEPTABLE_RECV_WINDOW = 300000 毫秒)。
    2. 对原始 body 重新解析、字母序排序、URL 编码,得到规范 body。
    3. &timestamp=<ts>&recvWindow=<rw> 拼到规范 body 末尾,对结果做 HMAC-SHA256,与 x-api-signature 做恒定时间比较。
  • 因为 timestamp/recvWindow 已纳入签名,攻击者无法在不重新签名的情况下篡改任一字段。
  • Webhook 验证的 Java / TypeScript 示例代码请参阅身份验证

示例请求

POST /ainepay/notify HTTP/1.1
Host: merchant.example.com
Content-Type: application/x-www-form-urlencoded
x-api-signature: <hex(HMAC-SHA256(notifySecret, body + "&timestamp=" + ts + "&recvWindow=" + rw))>
x-api-timestamp: 1760000300000
x-api-recv-window: 5000

chain=ETH&coin=USDT&created=1760000000000&expired=1760000600000&merchantId=20001&orderId=ORDER_10001&qty=88.00&status=PAID&updated=1760000300000&userId=U_90001

预期响应

字段类型描述
HTTP 状态integer返回任何 2xx 状态以确认成功接收。
HTTP/1.1 200 OK
Content-Type: text/plain

ok

注意事项

  • orderId 幂等处理 Webhook。
  • 将 Webhook 视为状态更新信号,然后使用查询订单确认最新订单状态后再执行最终业务操作。
  • 如果签名无效,不要信任该数据。