地址转账监听 · 接口详情
交易查询模块
交易查询模块提供对链上交易数据的多维度查询能力,支持按地址查询历史列表、批量查询交易详情,以及跨链聚合查询。
接口列表
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /tx/api/v1/transfers/query | 按地址查询交易列表(游标分页) |
| POST | /tx/api/v1/transfers/multi-chain | 多链多地址聚合查询 |
| POST | /tx/api/v1/transfers/details | 按交易哈希批量查询详情 |
| GET | /tx/api/v1/transfers/detail | 查询单笔交易详情 V2 |
地址交易查询
接口路径:POST /tx/api/v1/transfers/query
用途
按单个地址查询其在指定链上的历史交易列表,支持按交易类型、代币过滤,使用游标方式分页。
请求体字段说明
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
address | string | 是 | - | 待查询的钱包地址 |
chain_type | string | 否 | - | 链类型,不填则跨链查询 |
chain_id | integer | 否 | - | 链 ID |
tx_type | string | 否 | "" | 交易类型过滤,空字符串表示不过滤 |
token | string | 否 | - | 代币合约地址,用于过滤特定代币的转账 |
limit | integer | 否 | 20 | 每次返回的最大记录数,范围 1~100 |
id | integer | 否 | - | 游标 ID,用于分页续查 |
示例
# 基本查询
curl -X POST "$BASE_URL/tx/api/v1/transfers/query" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"chain_type": "ethereum",
"chain_id": 1,
"address": "0x1234567890abcdef1234567890abcdef12345678",
"limit": 20
}'
# 按代币过滤(查询 USDT 转账)
curl -X POST "$BASE_URL/tx/api/v1/transfers/query" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"chain_type": "ethereum",
"chain_id": 1,
"address": "0x1234...",
"token": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}'
响应
{
"code": 1,
"msg": "success",
"data": [
{
"chain_type": "ethereum",
"chain_id": 1,
"height": 21000000,
"tx_time": 1745000000,
"tx_hash": "0xabc123...",
"sender": "0x1234...",
"receiver": "0x5678...",
"amount": "1000000000000000000",
"symbol": "ETH",
"decimals": 18,
"tx_status": "success",
"transfer_type": "native",
"token_transfers": [],
"from_details": [],
"to_details": [],
"internal_transactions": []
}
]
}
注意:此接口成功时
code为1,消息字段为msg,与其他接口略有不同。
多地址聚合查询
接口路径:POST /tx/api/v1/transfers/multi-chain
用途
同时查询多条链、多个地址的交易记录,结果聚合后统一返回。
请求体字段说明
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
addresses | array | 是 | - | 多链地址分组列表,至少一项,最多 10 组 |
addresses[].chain_type | string | 是 | - | 链类型 |
addresses[].chain_id | integer | 是 | - | 链 ID |
addresses[].address | string[] | 是 | - | 该链下的地址数组,每组最多 20 个地址 |
limit | integer | 否 | 20 | 返回的最大记录数,范围 1~100 |
id | integer | 否 | - | 游标 ID,用于分页续查 |
示例
curl -X POST "$BASE_URL/tx/api/v1/transfers/multi-chain" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"addresses": [
{"chain_type": "ethereum", "chain_id": 1, "address": ["0xabc...001", "0xabc...002"]},
{"chain_type": "bsc", "chain_id": 56, "address": ["0xdef...003"]},
{"chain_type": "solana", "chain_id": 1, "address": ["SolanaAddress..."]}
],
"limit": 20
}'
响应
与 /tx/api/v1/transfers/query 格式相同,data 为聚合后的交易记录数组。
交易详情批量查询
接口路径:POST /tx/api/v1/transfers/details
用途
根据交易哈希批量查询交易详情。
请求体字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
chain_type | string | 是 | 链类型 |
chain_id | integer | 是 | 链 ID |
tx_hash | string 或 string[] | 是 | 单个交易哈希或哈希数组 |
示例
# 查询单笔交易
curl -X POST "$BASE_URL/tx/api/v1/transfers/details" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"chain_type": "ethereum", "chain_id": 1, "tx_hash": "0xabc123..."}'
# 批量查询多笔交易
curl -X POST "$BASE_URL/tx/api/v1/transfers/details" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"chain_type": "ethereum", "chain_id": 1, "tx_hash": ["0xabc123...", "0xdef456..."]}'
单笔交易详情查询
接口路径:GET /tx/api/v1/transfers/detail
用途
查询单笔交易的完整详情(V2 版本)。与 /tx/api/v1/transfers/details 的主要区别:
- 采用 GET 请求,参数通过 Query String 传递
- 支持
no_cache参数强制回源:当数据库中无记录时,可按链实时拉取并写入缓存 - 回源成功后会自动将数据写入数据库缓存
- 返回的数据结构采用混合字段命名(历史兼容格式,部分字段为 camelCase)
请求参数
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
chain_type | query | string | 是 | 链类型 |
chain_id | query | integer | 是 | 链 ID |
tx_hash | query | string | 是 | 交易哈希,支持带或不带 0x 前缀 |
no_cache | query | string | 否 | 传 true 或 1 时跳过本地缓存直接回源 |
示例
# 正常查询
curl "$BASE_URL/tx/api/v1/transfers/detail?chain_type=ethereum&chain_id=1&tx_hash=0xabc123..."
# 强制回源查询
curl "$BASE_URL/tx/api/v1/transfers/detail?chain_type=ethereum&chain_id=1&tx_hash=0xabc123...&no_cache=true"
响应(找到交易)
{
"code": 0,
"msg": "success",
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"height": 21000000,
"txTime": 1745000000000,
"txhash": "0xabc123...",
"sender": "0x1234...",
"fee_payer": "0x1234...",
"receiver": "0x5678...",
"transfer_type": "native",
"gasLimit": "21000",
"gasUsed": "21000",
"gasPrice": "20000000000",
"max_fee_per_gas": "30000000000",
"max_priority_fee_per_gas": "1000000000",
"txFee": "420000000000000",
"nonce": "42",
"symbol": "ETH",
"decimals": 18,
"amount": "1000000000000000000",
"txStatus": "success",
"methodId": "",
"methodCall": "",
"l1OriginHash": "",
"fromDetails": [],
"toDetails": [],
"internalTransactionDetails": [],
"tokenTransferDetails": [],
"listenAddress": null,
"is_reorg_resend": false
}
}
响应(交易不存在)
{
"code": 0,
"msg": "success",
"data": null
}
交易数据结构详解
TransactionDetail(列表查询返回格式)
/tx/api/v1/transfers/query、/tx/api/v1/transfers/multi-chain、/tx/api/v1/transfers/details 接口返回的交易格式。
主体字段:
| 字段 | 类型 | 说明 |
|---|---|---|
chain_type | string | 归一化后的链类型,小写 |
chain_id | integer | 链 ID |
height | integer | null | 区块高度 |
tx_time | integer | null | 交易时间,秒级 Unix 时间戳 |
tx_hash | string | 交易哈希 |
tx_version | integer | null | 交易版本号(Solana 等使用) |
sender | string | null | 发送方地址 |
fee_payer | string | null | 手续费支付方地址(Solana 场景) |
receiver | string | null | 接收方地址 |
transfer_type | string | null | 交易类型,如 native(原生转账)、token(代币转账) |
amount | string | null | 交易金额,字符串格式避免精度丢失 |
symbol | string | null | 主币或代币符号,如 ETH、BNB |
decimals | integer | null | 精度位数,如 18 |
tx_status | string | null | 交易状态:success、failed、pending |
tx_fee | string | null | 交易手续费 |
gas_limit | string | null | Gas 上限(EVM) |
gas_used | string | null | 实际消耗 Gas(EVM) |
gas_price | string | null | Gas 单价(EVM) |
max_fee_per_gas | string | null | EIP-1559 最大 Gas 单价 |
max_priority_fee_per_gas | string | null | EIP-1559 优先费单价 |
nonce | string | null | 账户 Nonce(EVM) |
method_id | string | null | 合约调用方法选择器(EVM) |
method_call | string | null | 合约方法名或调用摘要 |
l1_origin_hash | string | null | 二层链对应的 L1 原始交易哈希 |
token_transfers | array | 代币转账明细列表 |
from_details | array | 输入地址明细(UTXO 模型) |
to_details | array | 输出地址明细(UTXO 模型) |
internal_transactions | array | 内部交易或 Solana 指令明细 |
token_transfers(代币转账明细):
| 字段 | 类型 | 说明 |
|---|---|---|
from_address | string | null | 代币转出地址 |
to_address | string | null | 代币转入地址 |
token_contract_address | string | null | 代币合约地址 |
symbol | string | null | 代币符号 |
amount | string | null | 转账数量 |
decimals | integer | null | 代币精度 |
is_from_contract | boolean | 转出方是否为合约地址 |
is_to_contract | boolean | 转入方是否为合约地址 |
from_token_address | string | null | 源 token 账户地址(Solana) |
to_token_address | string | null | 目标 token 账户地址(Solana) |
mint | string | null | Solana Mint 地址 |
program_id | string | null | Solana Program ID |
from_details(输入地址明细,UTXO 模型):
| 字段 | 类型 | 说明 |
|---|---|---|
address | string | null | 输入地址 |
amount | string | null | 输入金额 |
is_contract | boolean | 是否为合约地址 |
vin_index | string | null | UTXO 输入索引 |
pre_vout_index | string | null | 前序交易输出索引 |
ref_tx_hash | string | null | 前序引用交易哈希 |
to_details(输出地址明细,UTXO 模型):
| 字段 | 类型 | 说明 |
|---|---|---|
address | string | null | 输出地址 |
amount | string | null | 输出金额 |
is_contract | boolean | 是否为合约地址 |
vout_index | string | null | UTXO 输出索引 |
internal_transactions(内部交易 / Solana 指令):
| 字段 | 类型 | 说明 |
|---|---|---|
from_address | string | null | 内部调用发送方 |
to_address | string | null | 内部调用接收方 |
amount | string | null | 内部调用金额 |
tx_status | string | null | 内部调用状态 |
program_id | string | null | Solana Program ID |
instr_index | integer | null | Solana 指令索引 |
depth | integer | null | Solana 调用深度 |
instruction | string | null | Solana 指令名称 |
description | string | null | 指令说明 |
V2 接口字段命名差异
/tx/api/v1/transfers/detail 接口返回的格式采用混合命名风格(历史兼容),与列表查询格式有所不同:
| V2 格式字段 | 对应列表格式字段 | 主要差异 |
|---|---|---|
txhash | tx_hash | 字段名不同 |
txTime | tx_time | camelCase,且为毫秒级时间戳 |
txStatus | tx_status | camelCase |
txFee | tx_fee | camelCase |
gasLimit | gas_limit | camelCase |
gasUsed | gas_used | camelCase |
gasPrice | gas_price | camelCase |
methodId | method_id | camelCase |
methodCall | method_call | camelCase |
l1OriginHash | l1_origin_hash | camelCase |
fromDetails | from_details | camelCase |
toDetails | to_details | camelCase |
internalTransactionDetails | internal_transactions | 字段名不同 |
tokenTransferDetails | token_transfers | 字段名不同 |
分页说明
交易列表查询使用游标(Cursor)分页而非传统的页码分页:
- 首次请求时不传
id参数,获取最新的 N 条记录 - 如果返回记录数量等于
limit,说明可能还有更多数据 - 取返回数组中最后一条记录的数据库内部
id传给下一次请求的id参数 - 继续请求,直到返回记录数量少于
limit为止
注意:游标分页不支持跳页,只能顺序向前翻页。
金额处理建议
所有金额字段均以字符串形式返回,以避免大数精度问题。展示时需结合 decimals 字段进行换算:
function formatAmount(amount, decimals) {
if (!amount || decimals === null) return '0';
const bigAmount = BigInt(amount);
const divisor = BigInt(10 ** decimals);
const intPart = bigAmount / divisor;
const fracPart = bigAmount % divisor;
return `${intPart}.${fracPart.toString().padStart(decimals, '0')}`;
}
// 示例:1000000000000000000 (decimals=18) → "1.000000000000000000"
console.log(formatAmount('1000000000000000000', 18));
DEX Pool 最近交易接口
DEX Pool 模块用于维护需要监听的 Pool 地址,并提供最近交易查询。相关订阅和推送仍使用地址管理接口或 WebSocket subscribe。
当链上交易处理成功后,系统会用交易参与地址匹配已启用的 Pool 地址。命中后将完整 TransactionResult 写入该 Pool 对应的 Durable Object FIFO 队列,队列容量默认最多保留最近 100 条。
查询 Pool 最近交易
接口路径:GET /tx/api/v1/dex-pools/{poolAddress}/trades
用途
公开查询指定 Pool 的最近交易记录,不需要额外管理员鉴权。
Query 参数
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
chainType | string | 是 | 无 | 链类型;兼容 chain_type。 |
chainId | number | 是 | 无 | 链 ID;兼容 chain_id。 |
limit | number | 否 | 100 | 返回最近交易条数,范围 1 到 100。 |
示例
curl "$BASE_URL/tx/api/v1/dex-pools/0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8/trades?chainType=evm&chainId=1&limit=50"
成功响应
{
"code": 0,
"message": "ok",
"data": {
"items": [
{
"chainType": "evm",
"chainId": 1,
"height": 19600000,
"txTime": 1710000000,
"txHash": "0x...",
"sender": "0xsender...",
"feePayer": "0xsender...",
"receiver": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
"transferType": "Token",
"gasLimit": "21000",
"gasUsed": "21000",
"gasPrice": "1000000000",
"maxFeePerGas": "",
"maxPriorityFeePerGas": "",
"txFee": "21000000000000",
"nonce": "1",
"symbol": "ETH",
"decimals": 18,
"amount": "0",
"txStatus": "success",
"methodId": "0xa9059cbb",
"methodCall": "0x...",
"fromDetails": [],
"toDetails": [],
"internalTransactionDetails": [],
"tokenTransferDetails": [
{
"from": "0xsender...",
"to": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
"isFromContract": false,
"isToContract": false,
"tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"symbol": "USDC",
"amount": "1000000",
"decimals": 6
}
]
}
]
}
}
返回交易字段
data.items 为 TransactionResult[],字段命名和 HTTP webhook 推送 body 中的数组元素一致,不使用 WebSocket 推送里的 chain_type、txhash、transfer_type 等字段名。可选字段值为 undefined 时 JSON 中会省略,值为 null 时会保留为 null。
主要字段包括:chainType、chainId、height、txTime、txHash、sender、feePayer、receiver、transferType、gasLimit、gasUsed、gasPrice、maxFeePerGas、maxPriorityFeePerGas、txFee、nonce、symbol、decimals、amount、txStatus、methodId、methodCall、fromDetails、toDetails、internalTransactionDetails、tokenTransferDetails。
地址管理模块
地址管理模块用于维护每个业务应用的监听地址名单。只有添加到名单中的地址,其链上交易才会被推送到对应应用的 WebSocket 订阅者或 Webhook 回调。
接口列表
| 方法 | 路径 | 说明 |
|---|---|---|
| PATCH | /tx/api/v1/addresses | Patch 模式:同时增删地址 |
| POST | /tx/api/v1/addresses | 批量添加地址 |
| POST | /tx/api/v1/addresses/batch-delete | 批量移除地址 |
| POST | /tx/api/v1/addresses/contains | 查询地址是否存在于名单 |
公共鉴权说明
所有地址受保护接口都通过 X-API-Key 识别调用方。服务会基于该 Key 完成接口鉴权、业务归属识别和计费统计。
| 方式 | 说明 | 示例 |
|---|---|---|
| 请求头 | 公共 API Key | X-API-Key: your-api-key |
注意:公网接入只需传入
X-API-Key,不需要额外的应用标识请求头或查询参数。
添加监听地址接口
接口路径:POST /tx/api/v1/addresses
用途
向指定应用的监听地址名单中批量添加地址。支持同时为多条链添加地址。
链特殊处理行为
- 其他非 EVM 链:会尝试将地址同步到平台内部监听组件;同步失败不会阻断本地入库。
请求体字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
wallets | array | 是 | 按链分组的地址列表,至少一项 |
wallets[].chain_type | string | 是 | 链类型,如 ethereum、solana、tron |
wallets[].address | string[] | 是 | 该链下的地址数组,至少一个地址 |
示例
# 添加以太坊地址
curl -X POST "$BASE_URL/tx/api/v1/addresses" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"wallets": [
{
"chain_type": "ethereum",
"address": ["0x1234...", "0xabcd..."]
}
]
}'
# 同时添加多链地址
curl -X POST "$BASE_URL/tx/api/v1/addresses" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"wallets": [
{"chain_type": "ethereum", "address": ["0x1234..."]},
{"chain_type": "tron", "address": ["TJDENsfBJs4RFETt1X1uyT9pBxdnAbFnbm"]},
{"chain_type": "solana", "address": ["SolanaAddress..."]}
]
}'
响应
{
"code": 0,
"message": "ok",
"data": "success"
}
移除监听地址
接口路径:POST /tx/api/v1/addresses/batch-delete
用途
从指定应用的监听地址名单中批量移除地址。移除后,该地址的新交易将不再推送给该应用。
请求体字段说明
与 /tx/api/v1/addresses 相同:wallets[].chain_type + wallets[].address。
示例
curl -X POST "$BASE_URL/tx/api/v1/addresses/batch-delete" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"wallets": [
{"chain_type": "ethereum", "address": ["0x1234..."]}
]
}'
响应
{
"code": 0,
"message": "ok",
"data": "success"
}
地址名单 Patch 更新
接口路径:PATCH /tx/api/v1/addresses
用途
以 Patch 模式同时对某条链执行地址的增删操作,在一次请求中完成地址名单的部分更新。
请求体字段说明
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
chain_type | string | 是 | - | 链类型,此接口一次只操作一条链 |
adds | string[] | 否 | [] | 要加入名单的地址列表 |
removes | string[] | 否 | [] | 要移出名单的地址列表 |
示例
curl -X PATCH "$BASE_URL/tx/api/v1/addresses" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"chain_type": "ethereum",
"adds": ["0xNewAddress001...", "0xNewAddress002..."],
"removes": ["0xOldAddress001..."]
}'
响应
{
"code": 0,
"message": "ok",
"data": "success"
}
地址存在性查询
接口路径:POST /tx/api/v1/addresses/contains
用途
查询某个地址是否已在指定链的地址名单中。
说明:当前版本此接口只验证地址在全局地址表中是否存在,不按 API Key 隔离过滤。
请求体字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
chain_type | string | 是 | 链类型 |
address | string | 是 | 待查询的地址 |
示例
curl -X POST "$BASE_URL/tx/api/v1/addresses/contains" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"chain_type": "ethereum", "address": "0x1234..."}'
响应
{
"code": 0,
"message": "ok",
"data": {
"is_exist": true
}
}
地址管理最佳实践
地址格式规范:
- EVM 链:使用
0x开头的 Hex 格式地址,建议使用 EIP-55 checksum 格式 - Solana:使用 Base58 格式地址
- Tron:使用 Base58Check 格式(以
T开头) - Bitcoin:使用标准 Bitcoin 地址格式(P2PKH、P2SH、Bech32 等)
地址名单与 WebSocket 订阅的关系:
- 通过
/tx/api/v1/addresses添加的地址会被持久化到数据库,应用重启后仍然有效 - WebSocket 连接建立后,服务会自动监听该应用名单中的所有地址
- 也可以在 WebSocket 连接建立后,通过
subscribe命令动态追加监听,但这种方式仅对当前连接有效,断线后不会自动恢复
推荐使用 HTTP 接口管理地址名单,WebSocket 的 subscribe/unsubscribe 命令仅用于临时的细粒度控制。
WebSocket 实时推送
WebSocket 模块提供链上交易的实时推送能力。客户端建立 WebSocket 连接后,服务会在监听地址产生链上交易时立即推送消息。
连接端点:
GET /tx/api/v1/transaction/ws
建立连接
请求说明
WebSocket 握手需要以下请求头:
| 请求头 | 类型 | 必填 | 说明 |
|---|---|---|---|
Upgrade | string | 是 | 固定值 websocket |
X-API-Key | string | 是 | 公共 API Key,用于鉴权和计费识别 |
X-ResendDuration | string | 否 | 历史消息重发时间窗口(秒),默认 180 |
注意:缺少
X-API-Key时,连接请求会返回400或鉴权失败。
连接示例
# 使用 wscat
wscat -c "wss://api.gelabs.org/tx/api/v1/transaction/ws" \
-H "X-API-Key: your-api-key"
连接成功消息
连接建立后,服务端立即推送:
{
"id": "msg-uuid-001",
"time": 1745000000000,
"type": "connected",
"code": 0,
"data": {
"clientId": "client-abc123",
"appId": "current-business-identity"
},
"msg": "success"
}
| 字段 | 说明 |
|---|---|
data.clientId | 当前连接在服务端的唯一标识,断线重连后会变化 |
data.appId | 当前连接绑定的调用方身份 |
连接失败
| HTTP 状态码 | 原因 | 处理建议 |
|---|---|---|
400 | 未提供 API Key | 确认已正确传入 X-API-Key |
426 | Upgrade: websocket 头缺失 | 确认使用 WebSocket 协议连接 |
消息格式
所有 WebSocket 消息均使用 JSON 格式,遵循以下统一结构:
{
"id": "消息唯一 ID",
"time": 1745000000000,
"type": "消息类型",
"code": 0,
"data": {},
"msg": "success"
}
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 消息唯一 ID,由发送方生成 |
time | integer | 消息时间戳,毫秒级 Unix 时间戳 |
type | string | 消息类型,决定消息的业务含义 |
code | integer | 业务状态码,0 表示成功,非 0 表示错误 |
data | object | null | 消息业务数据 |
msg | string | 文本消息,成功时通常为 success |
客户端命令
客户端可以向服务端发送以下命令。每条命令都需要提供唯一的 id 字段,服务端的回执会使用相同的 id 值。
ping(心跳)
发送心跳以保持连接活跃。
发送:
{
"id": "ping-001",
"type": "ping",
"data": {}
}
服务端回执:
{
"id": "ping-001",
"time": 1745000000000,
"type": "pong",
"code": 0,
"data": null,
"msg": "success"
}
subscribe(订阅地址)
订阅指定地址在指定链上的实时交易推送。
说明:通过此命令订阅的地址仅对当前连接有效,连接断开后不会保存。如需持久化地址订阅,请使用地址受保护接口提前将地址加入名单。
发送:
{
"id": "cmd-001",
"type": "subscribe",
"data": {
"address": "0x1234567890abcdef1234567890abcdef12345678",
"chain_type": "ethereum"
}
}
命令参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
data.address | string | 是 | 待订阅的地址 |
data.chain_type | string | 是 | 链类型,服务端会转为小写 |
成功回执:
{
"id": "cmd-001",
"type": "subscribe",
"code": 0,
"data": {"API Key": "current-business-identity", "address": "0x1234...", "chain_type": "ethereum"},
"msg": "success"
}
错误回执:
{
"id": "cmd-001",
"type": "subscribe",
"code": 400,
"data": null,
"msg": "address and chain_type required"
}
unsubscribe(取消订阅)
取消对指定地址的实时交易订阅。
发送(取消特定链):
{
"id": "cmd-002",
"type": "unsubscribe",
"data": {
"address": "0x1234...",
"chain_type": "ethereum"
}
}
发送(取消所有链,省略 chain_type):
{
"id": "cmd-002",
"type": "unsubscribe",
"data": {
"address": "0x1234..."
}
}
命令参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
data.address | string | 是 | 待取消订阅的地址 |
data.chain_type | string | 否 | 链类型,不填则取消该地址所有链的订阅 |
成功回执:
{
"id": "cmd-002",
"type": "unsubscribe",
"code": 0,
"data": {"address": "0x1234...", "chainType": "ethereum"},
"msg": "success"
}
取消所有链时,chainType 为 null。
getTxHash(查询交易详情)
通过 WebSocket 连接查询单笔交易的完整详情。
发送:
{
"id": "cmd-003",
"type": "getTxHash",
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"txHash": "0xabc123..."
}
}
命令参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
data.chain_type | string | 是 | 链类型 |
data.chain_id | integer | 是 | 链 ID |
data.txHash | string | 否 | 交易哈希 |
data.messageId | string | 否 | 实时推送消息的唯一 ID,优先使用此字段 |
建议:优先使用
messageId(即推送消息的id字段值)查询,服务端可更精确地定位记录。
错误回执(交易不存在):
{
"id": "cmd-003",
"type": "getTxHash",
"code": 404,
"data": null,
"msg": "transaction not found"
}
transactionACK(确认已处理交易)
客户端收到 transaction 消息并成功处理后,应发送 ACK 确认。服务端收到 ACK 后会停止对该笔交易的重发逻辑。
重要:如果客户端长时间未发送 ACK,服务端可能在客户端重连后重新推送未确认的交易,以确保消息不丢失。
发送:
{
"id": "ack-001",
"type": "transactionACK",
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"txHash": "0xabc123..."
}
}
成功回执:
{
"id": "ack-001",
"type": "transactionACK",
"code": 0,
"data": {"txHash": "0xabc123..."},
"msg": "success"
}
服务端推送消息
transaction(实时交易推送)
当监听地址产生链上交易时,服务端主动推送:
{
"id": "msg-tx-uuid-001",
"time": 1745000000000,
"type": "transaction",
"code": 0,
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"height": 21000000,
"txTime": 1745000000000,
"txhash": "0xabc123...",
"sender": "0x1234...",
"fee_payer": "0x1234...",
"receiver": "0x5678...",
"transfer_type": "native",
"gasLimit": "21000",
"gasUsed": "21000",
"gasPrice": "20000000000",
"max_fee_per_gas": "30000000000",
"max_priority_fee_per_gas": "1000000000",
"txFee": "420000000000000",
"nonce": "42",
"symbol": "ETH",
"decimals": 18,
"amount": "1000000000000000000",
"txStatus": "success",
"methodId": "",
"methodCall": "",
"fromDetails": [],
"toDetails": [],
"internalTransactionDetails": null,
"tokenTransferDetails": null,
"listenAddress": ["0x1234..."],
"is_reorg_resend": false
},
"msg": "success"
}
交易消息关键字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
data.listenAddress | string[] | 命中监听规则的地址列表,一笔交易可能命中多个地址 |
data.is_reorg_resend | boolean | 是否为链重组后的重发消息,true 时需检查本地记录 |
data.tokenTransferDetails | array | null | 代币转账明细列表,ERC-20 转账时包含具体转账信息 |
data.txTime | integer | 交易时间戳,毫秒级 |
is_reorg_resend 说明:
当值为 true 时,表示此交易因**链重组(Reorg)**被重新推送。建议检查本地是否已存在该 txhash 的记录,并根据需要更新区块高度等信息。
ERC-20 代币转账消息示例:
{
"id": "msg-tx-002",
"type": "transaction",
"code": 0,
"data": {
"chain_type": "ethereum",
"txhash": "0xdef456...",
"transfer_type": "token",
"tokenTransferDetails": [
{
"from": "0x1234...",
"to": "0x5678...",
"isFromContract": false,
"isToContract": false,
"tokenContractAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"amount": "1000000000",
"decimals": 6,
"fromTokenAddress": "",
"toTokenAddress": "",
"mint": "",
"programId": ""
}
],
"listenAddress": ["0x1234..."],
"is_reorg_resend": false
},
"msg": "success"
}
HTTP 辅助接口
WebSocket 连接状态查询
接口路径:GET /tx/api/v1/transaction/ws/status
查询指定应用的 WebSocket 连接状态。
curl "$BASE_URL/tx/api/v1/transaction/ws/status" \
-H "X-API-Key: your-api-key"
调用方身份由 X-API-Key 识别;公网接入不需要额外传入应用标识查询参数。
响应:
{
"code": 0,
"message": "ok",
"data": {
"appId": "current-business-identity",
"connectedClients": 2,
"clients": ["client-abc123", "client-def456"],
"details": [
{
"clientId": "client-abc123",
"connectedAt": 1745000000000,
"uptime": 3600,
"pendingTxCount": 0
}
]
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
connectedClients | integer | 当前在线客户端数量 |
details[].uptime | integer | 已存活秒数 |
details[].pendingTxCount | integer | 尚未收到 ACK 的待确认交易数量 |
WebSocket 消息重放
接口路径:POST /tx/api/v1/transaction/ws/replay
手动重放一条漏发的交易消息。服务端会:
- 将消息幂等写入数据库
- 推送给当前在线的 WebSocket 订阅者
- 并行触发 Webhook 回调
请求体为一条完整的 WsTransactionMessage 格式消息(与服务端推送的 transaction 消息格式相同)。
响应:
{
"code": 0,
"message": "ok",
"data": {
"processed": true,
"txhash": "0xabc123..."
}
}
错误处理
WebSocket 命令的错误以相同的 JSON 格式通过 WebSocket 消息返回,code 字段为非 0:
{
"id": "原始命令的 id",
"type": "命令类型",
"code": 400,
"data": null,
"msg": "错误描述"
}
常见错误汇总:
| 命令 | code | msg |
|---|---|---|
subscribe | 400 | address and chain_type required |
unsubscribe | 400 | address required |
getTxHash | 400 | chain_type, chain_id, txHash required |
getTxHash | 404 | transaction not found |
transactionACK | 400 | chain_type and messageId/txHash required |
最佳实践
心跳保活
建议每 30 秒发送一次 ping 命令:
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ id: `ping-${Date.now()}`, type: 'ping', data: {} }));
}
}, 30000);
断线重连
function connect() {
const ws = new WebSocket(WS_URL, { headers: { 'X-API-Key': API_KEY } });
ws.on('close', () => {
console.log('连接断开,5 秒后重连...');
setTimeout(connect, 5000);
});
return ws;
}
ACK 策略
- 及时 ACK:收到
transaction消息并完成业务处理后,立即发送transactionACK - 避免漏 ACK:如果业务处理耗时较长,可先 ACK 再异步处理
- ACK 去重:业务层应以
txhash + chain_type + chain_id为唯一键做幂等处理
地址订阅策略
| 方式 | 持久性 | 适用场景 |
|---|---|---|
HTTP 地址管理(/tx/api/v1/addresses) | 持久,重启后有效 | 常规业务地址的长期监听 |
WebSocket subscribe 命令 | 临时,仅当前连接有效 | 临时调试或动态细粒度控制 |
并发连接
同一个 API Key 对应的业务身份支持多个客户端同时连接,服务端会向所有在线连接广播交易消息。适用于多实例水平扩展或主备切换场景(需业务层做幂等处理)。