回调(Webhook)

适用对象:集成平台事件推送的第三方开发者。本文档说明回调结构、事件类型、返回要求、重试策略与接入配置。

概览

当平台发生事件时,会通过 HTTP POST 调用你配置的回调地址(callbackUrl)。你需要:

  1. 接收并解析 JSON 数据;

  2. 根据 X-EVENT-TYPE 识别事件类型;

  3. 成功处理后 返回 HTTP 200

  4. 否则平台将按重试策略重新通知。


配置回调地址

  • 入口位置:进入 用户中心 → API 设置 页面。

  • 配置项:填写 callbackUrl 并勾选要订阅的事件类型。

  • 协议:支持 HTTPHTTPS

  • 路径:平台通过请求头 X-EVENT-TYPE 标识事件类型。

  • 不可通过 API 动态订阅


请求头说明

平台每次回调都会附带以下 HTTP 头:

Header 名称
描述

X-EVENT-ID

事件唯一 ID(幂等键)

X-EVENT-TYPE

事件类型(枚举 EventType)

X-EVENT-VERSION

事件版本号


事件结构(JSON)

平台推送的回调请求体为 JSON,顶层字段采用 snake_case

{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": { /* 事件对应的数据体 */ }
}

事件类型(EventType)

当前有效事件类型:EVENT_BALANCEEVENT_TRON_MATE_SUBSCRIPTIONEVENT_DELEGATION(如收到未知类型,请记录并忽略)。

示例:余额变动(EVENT_BALANCE)

{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": {
    "balance_type": "BALANCE_CHANGE_TRANSFER",
    "billing_type": "BILLING_ENERGY",
    "coin_type": "USDT",
    "amount_sun": 1000000,
    "balance": 500000000,
    "balance_usdt": 2000000,
    "timestamp": 1760505600,
    "remark": "transfer in"
  }
}

示例:订阅(EVENT_TRON_MATE_SUBSCRIPTION)

{
  "event_type": "EVENT_TRON_MATE_SUBSCRIPTION",
  "event_id": "22334455-6677-8899-aabb-ccddeeff",
  "data": {
    "payment_amount_sun": 5000000,
    "payment_timestamp": 1760505600,
    "subscribe_type": "SUBSCRIBE_PRO",
    "address": "TGxxx..."
  }
}

回调请求格式

  • 方法POST

  • Content-Typeapplication/json; charset=utf-8

  • 请求头:包含 X-EVENT-IDX-EVENT-TYPEX-EVENT-VERSION

示例请求

POST /callback HTTP/1.1
Host: example.com
Content-Type: application/json
X-EVENT-ID: aabbccdd-1122-3344-5566-77889900
X-EVENT-TYPE: EVENT_BALANCE
X-EVENT-VERSION: 2025-01-01

{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": {
    "balance_type": "BALANCE_CHANGE_TRANSFER",
    "billing_type": "BILLING_ENERGY",
    "coin_type": "USDT",
    "amount_sun": 1000000,
    "balance": 500000000,
    "balance_usdt": 2000000,
    "timestamp": 1760505600,
    "remark": "transfer in"
  }
}

事件数据定义:


返回要求

⚠️ NOTICE: Please return success to notify the notification server after successfully receiving the callback request. After the notification server receives success, the notification stops.

  • 成功接收后,必须返回:

    HTTP/1.1 200 OK
    Content-Type: text/plain; charset=utf-8
    
  • 平台以返回 200 为成功,否则将重试。


重试机制

若响应非 200 ,系统会进行重试。

重试次数与间隔

10 次通知,间隔如下:

0s / 15s / 30s / 3m / 10m / 20m / 30m / 60m / 3h / 6h

若连续 10 次均失败,则系统放弃并记录。


幂等处理建议

  • 请使用 X-EVENT-ID 作为幂等键。

  • 对于已处理事件,应直接返回 200


示例代码

Node.js (Express)

import express from 'express';
const app = express();
app.use(express.json());
const processed = new Set();

app.post('/callback', (req, res) => {
  const eventId = req.header('X-EVENT-ID');
  if (processed.has(eventId)) return res.status(200).type('text/plain').send('success');
  processed.add(eventId);

  const evt = req.body; // { event_type, data }
  // TODO: 处理事件

  res.status(200).type('text/plain').send('success');
});

app.listen(8080);

Java (Spring Boot)

@RestController
public class WebhookController {
  private final Set<String> processed = Collections.synchronizedSet(new HashSet<>());

  @PostMapping(value = "/callback", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
  public ResponseEntity<String> handle(@RequestHeader("X-EVENT-ID") String id,
                                       @RequestBody Map<String, Object> evt) {
    synchronized (processed) {
      if (processed.contains(id)) return ResponseEntity.ok("success");
      processed.add(id);
    }

    // TODO: 事件处理逻辑

    return ResponseEntity.ok("success");
  }
}

Python (FastAPI)

from fastapi import FastAPI, Request, Header, Response
app = FastAPI()
processed = set()

@app.post("/callback")
async def webhook(req: Request, x_event_id: str = Header(None)):
    if x_event_id in processed:
        return Response(content="success", media_type="text/plain")
    processed.add(x_event_id)

    evt = await req.json()
    # TODO: 事件处理

    return Response(content="success", media_type="text/plain")

FAQ

Q1:返回 JSON 可以吗? 可以。只要返回的HTTP状态为200即可。

Q2:HTTP 支持吗? 支持 HTTP 与 HTTPS。

Q3:可否动态订阅? 不支持,仅能在用户中心配置。

Q4:如何分发不同事件? 根据请求头 X-EVENT-TYPE 实现逻辑分支。

Q5:事件会乱序吗? 系统尽量保证同类事件顺序,但不作绝对保证。

Q6:事件版本如何处理? 根据 X-EVENT-VERSION 选择解析方式,未知字段请忽略。


版本:v1.1.1(2025-10-21)

Last updated

Was this helpful?