Skip to main content

Address transfer monitoring — API reference

Transaction query module

The transaction query module provides multi-dimensional queries for on-chain transaction data, including historical lists by address, batch transaction detail queries, and cross-chain aggregate queries.

API list

MethodPathDescription
POST/tx/api/v1/transfers/queryQuery transaction list by address with cursor pagination
POST/tx/api/v1/transfers/multi-chainMulti-chain and multi-address aggregate query
POST/tx/api/v1/transfers/detailsBatch query details by transaction hash
GET/tx/api/v1/transfers/detailQuery single transaction detail, V2

Address transaction query

API path: POST /tx/api/v1/transfers/query

Purpose

Queries the historical transaction list for one address on a specified chain. It supports filtering by transaction type and token, and uses cursor-based pagination.

Request body fields

FieldTypeRequiredDefaultDescription
addressstringYes-Wallet address to query.
chain_typestringNo-Chain type. If omitted, the service performs a cross-chain query.
chain_idintegerNo-Chain ID.
tx_typestringNo""Transaction type filter. Empty string means no filtering.
tokenstringNo-Token contract address used to filter a specific token transfer.
limitintegerNo20Maximum number of returned records. Range: 1~100.
idintegerNo-Cursor ID for pagination continuation.

Example

# Basic query.
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
}'

# Filter by token to query USDT transfers.
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"
}'

Response

{
"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": []
}
]
}

This API returns code: 1 on success and uses msg, which differs from some other APIs.


Multi-address aggregate query

API path: POST /tx/api/v1/transfers/multi-chain

Purpose

Queries transaction records for multiple chains and multiple addresses and returns the aggregated result.

Request body fields

FieldTypeRequiredDefaultDescription
addressesarrayYes-Multi-chain address groups. At least 1 group and at most 10 groups.
addresses[].chain_typestringYes-Chain type.
addresses[].chain_idintegerYes-Chain ID.
addresses[].addressstring[]Yes-Address array for this chain. At most 20 addresses per group.
limitintegerNo20Maximum returned records. Range: 1~100.
idintegerNo-Cursor ID for pagination continuation.

Example

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
}'

Response

The response format is the same as /tx/api/v1/transfers/query. data is the aggregated transaction record array.


Batch transaction detail query

API path: POST /tx/api/v1/transfers/details

Purpose

Batch queries transaction details by transaction hash.

Request body fields

FieldTypeRequiredDescription
chain_typestringYesChain type.
chain_idintegerYesChain ID.
tx_hashstring or string[]YesA single transaction hash or an array of hashes.

Example

# Query one transaction.
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..."}'

# Batch query multiple transactions.
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..."]}'

Single transaction detail query

API path: GET /tx/api/v1/transfers/detail

Purpose

Queries the full details of one transaction, V2. Main differences from /tx/api/v1/transfers/details:

  • Uses GET with query string parameters.
  • Supports no_cache to force an origin fetch. If there is no local database record, the service can fetch by chain and write the result into cache.
  • Writes the data into the database cache after a successful origin fetch.
  • Returns a mixed field naming structure for historical compatibility. Some fields are camelCase.

Request parameters

NameLocationTypeRequiredDescription
chain_typequerystringYesChain type.
chain_idqueryintegerYesChain ID.
tx_hashquerystringYesTransaction hash, with or without the 0x prefix.
no_cachequerystringNoPass true or 1 to skip local cache and fetch from origin.

Example

# Normal query.
curl "$BASE_URL/tx/api/v1/transfers/detail?chain_type=ethereum&chain_id=1&tx_hash=0xabc123..."

# Force origin fetch.
curl "$BASE_URL/tx/api/v1/transfers/detail?chain_type=ethereum&chain_id=1&tx_hash=0xabc123...&no_cache=true"

Response when the transaction is found

{
"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
}
}

Response when the transaction does not exist

{
"code": 0,
"msg": "success",
"data": null
}

Transaction data structure

TransactionDetail returned by list queries

The /tx/api/v1/transfers/query, /tx/api/v1/transfers/multi-chain, and /tx/api/v1/transfers/details APIs return this transaction format.

Main fields:

FieldTypeDescription
chain_typestringNormalized lowercase chain type.
chain_idintegerChain ID.
heightinteger | nullBlock height.
tx_timeinteger | nullTransaction time as a second-level Unix timestamp.
tx_hashstringTransaction hash.
tx_versioninteger | nullTransaction version, used by chains such as Solana.
senderstring | nullSender address.
fee_payerstring | nullFee payer address, mainly for Solana.
receiverstring | nullReceiver address.
transfer_typestring | nullTransaction type, such as native or token.
amountstring | nullTransaction amount as a string to avoid precision loss.
symbolstring | nullNative currency or token symbol, such as ETH or BNB.
decimalsinteger | nullDecimal places, such as 18.
tx_statusstring | nullTransaction status: success, failed, or pending.
tx_feestring | nullTransaction fee.
gas_limitstring | nullGas limit for EVM chains.
gas_usedstring | nullActual gas used for EVM chains.
gas_pricestring | nullGas price for EVM chains.
max_fee_per_gasstring | nullEIP-1559 max fee per gas.
max_priority_fee_per_gasstring | nullEIP-1559 max priority fee per gas.
noncestring | nullAccount nonce for EVM chains.
method_idstring | nullContract method selector for EVM calls.
method_callstring | nullContract method name or call summary.
l1_origin_hashstring | nullOriginal L1 transaction hash for L2 chains.
token_transfersarrayToken transfer details.
from_detailsarrayInput address details for UTXO-style data.
to_detailsarrayOutput address details for UTXO-style data.
internal_transactionsarrayInternal transactions or Solana instruction details.

token_transfers:

FieldTypeDescription
from_addressstring | nullToken source address.
to_addressstring | nullToken destination address.
token_contract_addressstring | nullToken contract address.
symbolstring | nullToken symbol.
amountstring | nullTransfer amount.
decimalsinteger | nullToken decimals.
is_from_contractbooleanWhether the source address is a contract.
is_to_contractbooleanWhether the destination address is a contract.
from_token_addressstring | nullSource token account address for Solana.
to_token_addressstring | nullDestination token account address for Solana.
mintstring | nullSolana mint address.
program_idstring | nullSolana program ID.

from_details, input details for UTXO-style data:

FieldTypeDescription
addressstring | nullInput address.
amountstring | nullInput amount.
is_contractbooleanWhether the address is a contract.
vin_indexstring | nullUTXO input index.
pre_vout_indexstring | nullPrevious transaction output index.
ref_tx_hashstring | nullReferenced previous transaction hash.

to_details, output details for UTXO-style data:

FieldTypeDescription
addressstring | nullOutput address.
amountstring | nullOutput amount.
is_contractbooleanWhether the address is a contract.
vout_indexstring | nullUTXO output index.

internal_transactions, internal calls or Solana instructions:

FieldTypeDescription
from_addressstring | nullInternal call sender.
to_addressstring | nullInternal call receiver.
amountstring | nullInternal call amount.
tx_statusstring | nullInternal call status.
program_idstring | nullSolana program ID.
instr_indexinteger | nullSolana instruction index.
depthinteger | nullSolana call depth.
instructionstring | nullSolana instruction name.
descriptionstring | nullInstruction description.

V2 field naming differences

The /tx/api/v1/transfers/detail API returns a mixed naming style for historical compatibility:

V2 fieldMatching list fieldMain difference
txhashtx_hashDifferent field name.
txTimetx_timecamelCase and millisecond timestamp.
txStatustx_statuscamelCase.
txFeetx_feecamelCase.
gasLimitgas_limitcamelCase.
gasUsedgas_usedcamelCase.
gasPricegas_pricecamelCase.
methodIdmethod_idcamelCase.
methodCallmethod_callcamelCase.
l1OriginHashl1_origin_hashcamelCase.
fromDetailsfrom_detailscamelCase.
toDetailsto_detailscamelCase.
internalTransactionDetailsinternal_transactionsDifferent field name.
tokenTransferDetailstoken_transfersDifferent field name.

Pagination

Transaction list queries use cursor pagination instead of page numbers:

  1. Do not pass id in the first request. The service returns the latest N records.
  2. If the returned record count equals limit, there may be more data.
  3. Use the database internal id of the last returned record as the next request's id.
  4. Continue until the returned record count is smaller than limit.

Cursor pagination does not support jumping to a page. It can only move forward sequentially.


Amount handling recommendations

All amount fields are returned as strings to avoid large-number precision loss. Convert display values with the decimals field:

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')}`;
}

// Example: 1000000000000000000 with decimals=18 becomes "1.000000000000000000".
console.log(formatAmount('1000000000000000000', 18));

DEX Pool recent trades API

The DEX Pool module maintains pool addresses that need monitoring and exposes a recent-trades query. Related subscriptions and pushes still use the address management APIs or WebSocket subscribe flow.

After an on-chain transaction is processed successfully, the service matches transaction participant addresses against enabled pool addresses. Matched transactions are written as full TransactionResult objects into the pool's Durable Object FIFO queue, which keeps up to the latest 100 records by default.

Query recent pool trades

API path: GET /tx/api/v1/dex-pools/{poolAddress}/trades

Purpose

Publicly queries recent trades for a specific pool. No additional administrator authentication is required.

Query parameters

FieldTypeRequiredDefaultDescription
chainTypestringYesNoneChain type; chain_type is also accepted.
chainIdnumberYesNoneChain ID; chain_id is also accepted.
limitnumberNo100Number of recent trades to return, from 1 to 100.

Example

curl "$BASE_URL/tx/api/v1/dex-pools/0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8/trades?chainType=evm&chainId=1&limit=50"

Successful response

{
"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
}
]
}
]
}
}

Returned transaction fields

data.items is TransactionResult[]. Field names match the array elements in the HTTP webhook body and do not use the WebSocket push names such as chain_type, txhash, or transfer_type. Optional fields whose value is undefined are omitted from JSON, while fields whose value is null are kept as null.

Main fields include: 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, and tokenTransferDetails.


Address management module

The address management module maintains the monitored address list for each business integration. Only addresses added to the list trigger transaction pushes to the corresponding WebSocket subscribers or Webhook callback.

API list

MethodPathDescription
PATCH/tx/api/v1/addressesPatch mode for adding and removing addresses in one request
POST/tx/api/v1/addressesBatch add addresses
POST/tx/api/v1/addresses/batch-deleteBatch remove addresses
POST/tx/api/v1/addresses/containsQuery whether an address exists in the list

Public authentication notes

All protected address APIs identify the caller through X-API-Key. The service uses this key for API authentication, business ownership identification, and billing statistics.

MethodDescriptionExample
Request headerPublic API keyX-API-Key: your-api-key

Public access only requires X-API-Key. No additional application identity header or query parameter is required.


Add monitored addresses API

API path: POST /tx/api/v1/addresses

Purpose

Batch adds addresses to the monitored address list for the current business identity. Multiple chains can be added in one request.

Chain-specific behavior

  • Other non-EVM chains: the service attempts to sync addresses to an internal platform monitoring component. Sync failures do not block local database writes.

Request body fields

FieldTypeRequiredDescription
walletsarrayYesAddress list grouped by chain. At least one item is required.
wallets[].chain_typestringYesChain type, such as ethereum, solana, or tron.
wallets[].addressstring[]YesAddress array for the chain. At least one address is required.

Example

# Add Ethereum addresses.
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..."]
}
]
}'

# Add addresses for multiple chains.
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..."]}
]
}'

Response

{
"code": 0,
"message": "ok",
"data": "success"
}

Remove monitored addresses

API path: POST /tx/api/v1/addresses/batch-delete

Purpose

Batch removes addresses from the monitored address list. After removal, new transactions for the address are no longer pushed to the current business identity.

Request body fields

Same as /tx/api/v1/addresses: wallets[].chain_type plus wallets[].address.

Example

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..."]}
]
}'

Response

{
"code": 0,
"message": "ok",
"data": "success"
}

Patch address list

API path: PATCH /tx/api/v1/addresses

Purpose

Uses patch mode to add and remove addresses for one chain in a single request.

Request body fields

FieldTypeRequiredDefaultDescription
chain_typestringYes-Chain type. This API operates on one chain at a time.
addsstring[]No[]Addresses to add to the list.
removesstring[]No[]Addresses to remove from the list.

Example

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..."]
}'

Response

{
"code": 0,
"message": "ok",
"data": "success"
}

Address existence query

API path: POST /tx/api/v1/addresses/contains

Purpose

Queries whether an address already exists in the address list for a specified chain.

In the current version, this API only checks whether the address exists in the global address table. It does not filter by API key isolation.

Request body fields

FieldTypeRequiredDescription
chain_typestringYesChain type.
addressstringYesAddress to query.

Example

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..."}'

Response

{
"code": 0,
"message": "ok",
"data": {
"is_exist": true
}
}

Address management best practices

Address format guidelines:

  • EVM chains: use hex addresses starting with 0x. EIP-55 checksum format is recommended.
  • Solana: use Base58 addresses.
  • Tron: use Base58Check addresses starting with T.
  • Bitcoin: use standard Bitcoin address formats, such as P2PKH, P2SH, and Bech32.

Relationship between the address list and WebSocket subscriptions:

  • Addresses added through /tx/api/v1/addresses are persisted in the database and remain effective after service restarts.
  • After a WebSocket connection is established, the service automatically monitors all addresses in the business identity's address list.
  • You can also use the WebSocket subscribe command to add temporary monitoring after connection establishment, but this is only effective for the current connection and is not restored after disconnection.

For regular business monitoring, use HTTP APIs to manage the address list. Use WebSocket subscribe and unsubscribe only for temporary fine-grained control.


WebSocket real-time push

The WebSocket module provides real-time on-chain transaction push. After a client establishes a WebSocket connection, the service immediately pushes messages when monitored addresses produce on-chain transactions.

Connection endpoint:

GET /tx/api/v1/transaction/ws

Establishing a connection

Request notes

The WebSocket handshake requires these request headers:

HeaderTypeRequiredDescription
UpgradestringYesFixed value: websocket.
X-API-KeystringYesPublic API key for authentication and billing identification.
X-ResendDurationstringNoHistorical message resend window in seconds. Default: 180.

If X-API-Key is missing, the connection request returns 400 or an authentication failure.

Connection example

# Use wscat.
wscat -c "wss://api.gelabs.org/tx/api/v1/transaction/ws" \
-H "X-API-Key: your-api-key"

Successful connection message

After the connection is established, the server immediately pushes:

{
"id": "msg-uuid-001",
"time": 1745000000000,
"type": "connected",
"code": 0,
"data": {
"clientId": "client-abc123",
"appId": "current-business-identity"
},
"msg": "success"
}
FieldDescription
data.clientIdUnique server-side identifier of the current connection. It changes after reconnecting.
data.appIdCaller identity bound to the current connection.

Connection failure

HTTP statusReasonRecommendation
400API key not provided.Confirm that X-API-Key is passed correctly.
426Upgrade: websocket header is missing.Confirm that the client connects through the WebSocket protocol.

Message format

All WebSocket messages use JSON and follow this envelope:

{
"id": "message unique ID",
"time": 1745000000000,
"type": "message type",
"code": 0,
"data": {},
"msg": "success"
}
FieldTypeDescription
idstringUnique message ID generated by the sender.
timeintegerMessage timestamp as a millisecond Unix timestamp.
typestringMessage type that determines business meaning.
codeintegerBusiness status code. 0 means success and non-zero means error.
dataobject | nullBusiness data.
msgstringText message. Successful responses usually use success.

Client commands

Clients can send the commands below to the server. Each command needs a unique id, and the server response uses the same id.

ping (heartbeat)

Sends a heartbeat to keep the connection active.

Send:

{
"id": "ping-001",
"type": "ping",
"data": {}
}

Server response:

{
"id": "ping-001",
"time": 1745000000000,
"type": "pong",
"code": 0,
"data": null,
"msg": "success"
}

subscribe (subscribe to an address)

Subscribes to real-time transaction pushes for a specified address on a specified chain.

Addresses subscribed through this command are only effective for the current connection and are not saved after disconnection. For persistent address subscription, add the address through the address management module in advance.

Send:

{
"id": "cmd-001",
"type": "subscribe",
"data": {
"address": "0x1234567890abcdef1234567890abcdef12345678",
"chain_type": "ethereum"
}
}

Command parameters:

FieldTypeRequiredDescription
data.addressstringYesAddress to subscribe.
data.chain_typestringYesChain type. The server converts it to lowercase.

Success response:

{
"id": "cmd-001",
"type": "subscribe",
"code": 0,
"data": {"API Key": "current-business-identity", "address": "0x1234...", "chain_type": "ethereum"},
"msg": "success"
}

Error response:

{
"id": "cmd-001",
"type": "subscribe",
"code": 400,
"data": null,
"msg": "address and chain_type required"
}

unsubscribe (unsubscribe)

Cancels the real-time transaction subscription for an address.

Send for a specific chain:

{
"id": "cmd-002",
"type": "unsubscribe",
"data": {
"address": "0x1234...",
"chain_type": "ethereum"
}
}

Send for all chains by omitting chain_type:

{
"id": "cmd-002",
"type": "unsubscribe",
"data": {
"address": "0x1234..."
}
}

Command parameters:

FieldTypeRequiredDescription
data.addressstringYesAddress to unsubscribe.
data.chain_typestringNoChain type. If omitted, all chain subscriptions for this address are canceled.

Success response:

{
"id": "cmd-002",
"type": "unsubscribe",
"code": 0,
"data": {"address": "0x1234...", "chainType": "ethereum"},
"msg": "success"
}

When all chains are canceled, chainType is null.


getTxHash (query transaction details)

Queries the full details of one transaction through the WebSocket connection.

Send:

{
"id": "cmd-003",
"type": "getTxHash",
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"txHash": "0xabc123..."
}
}

Command parameters:

FieldTypeRequiredDescription
data.chain_typestringYesChain type.
data.chain_idintegerYesChain ID.
data.txHashstringNoTransaction hash.
data.messageIdstringNoUnique ID of the real-time push message. Prefer this field when available.

Prefer messageId, the id value of the push message, so the server can locate the record more accurately.

Error response when the transaction does not exist:

{
"id": "cmd-003",
"type": "getTxHash",
"code": 404,
"data": null,
"msg": "transaction not found"
}

transactionACK (confirm processed transaction)

After receiving and processing a transaction message, the client should send an ACK. After receiving the ACK, the server stops retrying that transaction.

If the client does not send ACK for a long time, the server may resend unacknowledged transactions after the client reconnects to prevent message loss.

Send:

{
"id": "ack-001",
"type": "transactionACK",
"data": {
"chain_type": "ethereum",
"chain_id": 1,
"txHash": "0xabc123..."
}
}

Success response:

{
"id": "ack-001",
"type": "transactionACK",
"code": 0,
"data": {"txHash": "0xabc123..."},
"msg": "success"
}

Server push messages

transaction (real-time transaction push)

When a monitored address has an on-chain transaction, the server pushes:

{
"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"
}

Key transaction message fields:

FieldTypeDescription
data.listenAddressstring[]Addresses that matched monitoring rules. One transaction may match multiple addresses.
data.is_reorg_resendbooleanWhether this is a resend after a chain reorganization. If true, check local records.
data.tokenTransferDetailsarray | nullToken transfer details. Present for ERC-20 transfers.
data.txTimeintegerTransaction timestamp in milliseconds.

is_reorg_resend notes:

When the value is true, the transaction is resent because of a chain reorganization. Check whether the local record for the same txhash already exists and update fields such as block height when needed.

ERC-20 token transfer message example:

{
"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 helper APIs

WebSocket connection status query

API path: GET /tx/api/v1/transaction/ws/status

Queries the WebSocket connection status for the current business identity.

curl "$BASE_URL/tx/api/v1/transaction/ws/status" \
-H "X-API-Key: your-api-key"

The caller identity is identified by X-API-Key. Public access does not require an additional application identity query parameter.

Response:

{
"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
}
]
}
}
FieldTypeDescription
connectedClientsintegerNumber of online clients.
details[].uptimeintegerLifetime in seconds.
details[].pendingTxCountintegerNumber of pending transactions that have not received ACK.

WebSocket message replay

API path: POST /tx/api/v1/transaction/ws/replay

Manually replays a missed transaction message. The server will:

  1. Idempotently write the message into the database.
  2. Push it to currently online WebSocket subscribers.
  3. Trigger Webhook callbacks in parallel.

The request body is a complete WsTransactionMessage, the same format as the server-pushed transaction message.

Response:

{
"code": 0,
"message": "ok",
"data": {
"processed": true,
"txhash": "0xabc123..."
}
}

Error handling

WebSocket command errors use the same JSON envelope and set code to a non-zero value:

{
"id": "original command id",
"type": "command type",
"code": 400,
"data": null,
"msg": "error description"
}

Common errors:

Commandcodemsg
subscribe400address and chain_type required
unsubscribe400address required
getTxHash400chain_type, chain_id, txHash required
getTxHash404transaction not found
transactionACK400chain_type and messageId/txHash required

Best practices

Heartbeat

Send a ping command every 30 seconds:

setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ id: `ping-${Date.now()}`, type: 'ping', data: {} }));
}
}, 30000);

Reconnect after disconnection

function connect() {
const ws = new WebSocket(WS_URL, { headers: { 'X-API-Key': API_KEY } });
ws.on('close', () => {
console.log('Connection closed, reconnecting in 5 seconds...');
setTimeout(connect, 5000);
});
return ws;
}

ACK strategy

  • ACK promptly: after receiving and processing a transaction message, send transactionACK immediately.
  • Avoid missing ACK: if business processing is slow, consider sending ACK first and processing asynchronously.
  • Deduplicate ACKs: use txhash + chain_type + chain_id as the business idempotency key.

Address subscription strategy

MethodPersistenceUse case
HTTP address management (/tx/api/v1/addresses)Persistent, effective after restartLong-term monitoring of regular business addresses
WebSocket subscribe commandTemporary, only effective for the current connectionTemporary debugging or dynamic fine-grained control

Concurrent connections

The business identity represented by the same API key supports multiple clients connected at the same time. The server broadcasts transaction messages to all online connections. This is suitable for horizontal scaling or active-standby switching, as long as the business layer handles messages idempotently.