Transfers · API reference
Base https://gateway.gelabs.org. Always X-API-Key.
HTTP queries sit in {code,message,data} with code 0 on success. WebSocket frames and webhook bodies do not use that envelope.
Addresses
| Method | Path | Purpose |
|---|---|---|
| GET | /tx/api/v1/addresses | List (page, pageSize, chain_type) |
| POST | /tx/api/v1/addresses | Add. wallets[]: chain_type, chain_id, address[] |
| POST | /tx/api/v1/addresses/batch-delete | Delete with the same shape |
| PATCH | /tx/api/v1/addresses | add / remove |
| POST | /tx/api/v1/addresses/contains | Already watched? |
HTTP watches persist. Live push also needs enable_ws / enable_webhook.
Excluded from push
Watches and history stay. For the same chain_type, a transfer is not sent over WebSocket or webhook when the sender, receiver, or a token-transfer from / to / contract is on this list.
| Method | Path | Purpose |
|---|---|---|
| GET | /tx/api/v1/addresses/exclusions | List (page, pageSize, chain_type) |
| POST | /tx/api/v1/addresses/exclusions | Add. wallets[] matches the watch body |
| POST | /tx/api/v1/addresses/exclusions/batch-delete | Remove with the same shape |
Queries
| Method | Path | Purpose |
|---|---|---|
| POST | /tx/api/v1/transfers/search | One address. Cursor id; filters tx_type (native / token / other), token |
| POST | /tx/api/v1/transfers/multi-chain | Many chains / addresses |
| POST | /tx/api/v1/transactions/batch-get | By tx_hash |
| GET | /tx/api/v1/transactions/{tx_hash} | One tx; query needs chain_type, chain_id |
search example:
{
"address": "0x...",
"chain_type": "evm",
"chain_id": 1,
"limit": 20
}
Push config
| Method | Path | Purpose |
|---|---|---|
| GET | /tx/api/v1/app/config | WS / webhook flags |
| PUT | /tx/api/v1/app/config | enable_ws, enable_webhook, webhook_url, webhook_secret |
| POST | /tx/api/v1/app/webhook/retry | Retry failed deliveries |
Webhook requires a public webhook_url. webhook_secret is optional; when set, every POST includes the Sign header.
{
"enable_ws": true,
"enable_webhook": true,
"webhook_url": "https://your-server.example/hooks/tx",
"webhook_secret": "your-secret"
}
Transfer object
data on a WebSocket type: transaction frame, and each item in the webhook array, describe the same transfer, but the JSON shape is not identical (see Webhook below).
The push chain family is evm / tvm / svm / utxo. Supported networks and chain_id values: Overview.
camelCase primary fields (prefer these for new integrations):
| Field | Type | Meaning |
|---|---|---|
chainType | string | Family, e.g. evm, tvm |
chainId | integer | Chain ID, e.g. Ethereum mainnet 1 |
txHash | string | Transaction hash |
txTime | integer | Tx time, Unix milliseconds |
height | integer | Block height |
sender | string | Sender |
receiver | string | Receiver |
feePayer | string | Fee payer |
amount | string | Native amount (string; do not parse as a JS number) |
symbol | string | Native symbol |
decimals | integer | Native decimals |
txStatus | string | On-chain status, e.g. success |
gasLimit / gasUsed / gasPrice / txFee | string | Gas and fee (strings) |
nonce | string | Transaction nonce |
transferType | string | NativeCoin / Token / Other; see table below |
methodId / methodCall | string | Contract method |
l1OriginHash | string | L1 origin hash (L2, etc.) |
listenAddress | string[] | Matched watch addresses; [] if none |
tokenTransferDetails | array | Token transfers (camelCase items) |
fromDetails | array | Multi-input details (camelCase) |
toDetails | array | Multi-output details (camelCase) |
internalTransactionDetails | array | Internal calls / instructions (camelCase) |
Common tokenTransferDetails[] fields: from, to, tokenContractAddress, symbol, amount, decimals, mint.
transferType
Classifies the primary transfer semantics of a transaction. All chain families (evm / tvm / svm / utxo) use the same values:
| Value | Meaning |
|---|---|
NativeCoin | Native coin transfer. Examples: plain ETH on EVM, TVM TransferContract (TRX), Bitcoin UTXO. Top-level amount / symbol / decimals are usually populated. |
Token | Token transfer. Examples: direct ERC-20 / TRC-20 transfer contract calls. Native amount is often "0"; see tokenTransferDetails for token amounts. |
Other | Other contract interactions: batch transfers, non-direct token calls, stake / freeze, etc. Token movements, if any, are in tokenTransferDetails; top-level fields may not reflect actual asset flow. |
Webhook snake_case transfer_type is the DB raw shape; legacy rows may use lowercase token. camelCase transferType is always PascalCase.
For /tx/api/v1/transfers/search, tx_type filters are case-insensitive: native / nativecoin → NativeCoin, token → Token, other → Other.
Webhook also emits snake_case (same meaning or DB raw shape, for legacy consumers):
| snake_case key | camelCase / notes |
|---|---|
chain_type, chain_id, tx_hash, tx_time, tx_status | Same as chainType, chainId, txHash, txTime, txStatus |
token_transfers, from_details, to_details | Same family as tokenTransferDetails, DB field names |
internal_transactions | Same family as internalTransactionDetails, DB shape |
tx_version, fee_payer, transfer_type | Raw pointer fields; may be null |
max_fee_per_gas, max_priority_fee_per_gas | EIP-1559; may be null |
gas_limit, gas_used, gas_price, tx_fee | Same as gasLimit, etc.; raw pointer shape |
method_id, method_call, l1_origin_hash | Same as methodId, etc.; raw pointer shape |
WebSocket data matches the webhook business fields, plus is_reorg_resend (true for reorg resends). There is no legacy txhash alias; read txHash / tx_hash. ACK with chain_type + txHash.
WebSocket
GET wss://gateway.gelabs.org/tx/ws
Header X-API-Key. To receive transaction pushes, PUT /tx/api/v1/app/config with enable_ws: true and add addresses over HTTP.
Every frame:
| Field | Type | Meaning |
|---|---|---|
id | string | Frame ID. Use as messageId when ACKing |
time | integer | Unix milliseconds |
type | string | See table below |
code | integer | 0 success; non-zero is an error |
data | object / null | Depends on type |
message | string | Human text. It is message, not msg |
type | Direction | Meaning |
|---|---|---|
connected | down | Handshake |
transaction | down | Hit; data is the transfer object |
transactionACK | up | Confirm receipt; stops resend |
ping / pong | both | JSON heartbeat; raw text ping also works |
subscribe / unsubscribe | up | Add / remove a persistent watch on this App |
getTxHash | up | Look up one tx by hash |
connected
{
"id": "c1",
"time": 1710000000000,
"type": "connected",
"code": 0,
"data": {
"clientId": "client-uuid",
"appId": "your-app-id"
},
"message": "success"
}
transaction
{
"id": "msg-1",
"time": 1710000000000,
"type": "transaction",
"code": 0,
"data": {
"chain_type": "evm",
"chain_id": 1,
"tx_hash": "0xabc...",
"txHash": "0xabc...",
"tx_time": 1710000000000,
"txTime": 1710000000000,
"height": 12345678,
"sender": "0x1111...",
"receiver": "0x2222...",
"amount": "1000000000000000000",
"symbol": "ETH",
"decimals": 18,
"tx_status": "success",
"listenAddress": ["0x1111..."],
"token_transfers": [],
"from_details": [],
"to_details": [],
"is_reorg_resend": false
},
"message": "success"
}
ACK immediately or the server resends:
{
"id": "ack-1",
"type": "transactionACK",
"data": {
"chain_type": "evm",
"txHash": "0xabc...",
"messageId": "msg-1"
}
}
chain_type is required. Provide at least one of txHash (or tx_hash) and messageId (or message_id, the downlink frame id). The server replies with the same type; code 0 means the ACK landed.
subscribe
{
"id": "sub-1",
"type": "subscribe",
"data": {
"address": "0x1234567890abcdef1234567890abcdef12345678",
"chain_type": "evm",
"chain_id": 1
}
}
On success data is {app_id, address, chain_type}. unsubscribe uses the same request shape; success data is {address, chainType}. Prefer HTTP for the watch list so disconnects do not surprise you.
Webhook
The server POSTs to your webhook_url. You do not poll.
Headers
| Header | Meaning |
|---|---|
Content-Type | application/json |
Sign | Equals the webhook_secret in config. Empty string if unset |
Compare Sign as plaintext. It is not an HMAC.
Body
The body is a JSON array. Each item includes both camelCase primary fields and snake_case compatibility keys (see Transfer object above). The example omits some raw fields that may be null:
[
{
"chain_type": "evm",
"chain_id": 1,
"tx_time": 1710000000000,
"tx_hash": "0xabc...",
"tx_status": "success",
"gas_limit": "21000",
"gas_used": "21000",
"gas_price": "1000000000",
"tx_fee": "21000000000000",
"token_transfers": [],
"from_details": [],
"to_details": [],
"internal_transactions": [],
"chainType": "evm",
"chainId": 1,
"txTime": 1710000000000,
"txHash": "0xabc...",
"height": 12345678,
"sender": "0x1111...",
"receiver": "0x2222...",
"feePayer": "0x1111...",
"amount": "1000000000000000000",
"symbol": "ETH",
"decimals": 18,
"txStatus": "success",
"gasLimit": "21000",
"gasUsed": "21000",
"gasPrice": "1000000000",
"txFee": "21000000000000",
"nonce": "7",
"listenAddress": ["0x1111..."],
"tokenTransferDetails": [],
"fromDetails": [],
"toDetails": [],
"internalTransactionDetails": []
}
]
Legacy integrations may keep reading chain_type / tx_hash; new integrations should prefer camelCase primary fields.
Your response
Return HTTP 2xx (body may be empty). Non-2xx or timeout triggers retry. Use POST /tx/api/v1/app/webhook/retry to replay failed deliveries.