Messages
{
"op": "subscribed",
"id": "whale-1",
"channel": "wallet-trades",
"updatePeriod": 0
}{
"op": "event",
"id": "whale-1",
"channel": "wallet-trades",
"data": {
"wallet": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj",
"id": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh:CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump:b",
"at": 1790539767000,
"chain": "solana",
"tokenAddress": "CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump",
"poolAddress": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS",
"isBuy": true,
"amountToken": 15915963.2,
"priceNative": 3.1415e-8,
"volumeNative": 0.5,
"volumeUsd": 75.02,
"feesNative": 0.000105,
"isWash": false,
"isRoutingHop": false,
"txHash": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh",
"block": 371204455,
"logIndex": 0
},
"asOf": 1790539767412,
"cursor": "v1.amun6v2l5lbes.2kx.mfq3c2y2"
}{
"op": "subscribe",
"channel": "wallet-trades",
"id": "whale-1",
"params": {
"chain": "solana",
"address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj"
}
}Wallets
Wallet Trades Stream
Every trade of the wallets you follow, pushed as it lands: one wallet or a list of up to 100 per subscription. Events carry the same fields as REST /v1/wallet/trades, plus the wallet.
WS channel: wallet-trades
Enabled on your key on request: contact us.
Every trade of the wallets you follow, pushed as it lands: one wallet or a list of up to 100 per subscription. Events carry the same fields as REST /v1/wallet/trades, plus the wallet.
Use it for copy trading, wallet trackers and alerts. For the positions of a wallet kept up to date, see the Wallet Positions Stream; for their live value and PnL, the Wallet Portfolio Stream.
Delivery model
- Events, as they land. There is no snapshot: the stream starts with the first trade that follows your subscription. Past trades are on REST.
- One event per transaction, token and side. A routed swap never doubles volumes: same rule as REST. Routed intermediate legs are delivered and flagged
isRoutingHop, so you choose to show or skip them. - One wallet on one chain per entry. A wallet followed on two chains is two entries.
Parameters
Give eitherchain and address, or wallets.
string
Public chain id,
evm:<id> or solana. Required with address. Example: solanastring
The wallet address (EVM hex, case-insensitive; Solana base58). Example:
DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzjobject[]
A list of 1 to 100 wallets,
[{ "chain": "...", "address": "..." }, ...], in place of chain and address. Each wallet counts as one subscription in the limit of your account. With a list, every message is "data": [trade, ...].integer
Milliseconds, 0 to 60000, default
0 (every trade as it lands). Above 0, one message per period carries every trade of the period in order, as "data": [trade, ...], for 1 credit. The ack carries the value applied (snapped up to 0, 100, 250, 500, 1000, 2000, 5000, 10000, 30000, 60000). See Choosing your pace.The trade
| Field | |
|---|---|
wallet | The wallet that traded |
id | Stable id of the trade: dedupe on it |
at | Time of the trade, ms |
chain, tokenAddress, poolAddress | Where it happened |
isBuy | true when the wallet bought the token |
amountToken, priceNative, volumeNative, volumeUsd | Size and price. volumeUsd is null when the USD rate is unknown, never 0 |
feesNative | Transaction fees, in the native asset |
isWash | Boolean on Solana, null on EVM |
isRoutingHop | true for an intermediate leg of a routed swap |
txHash, block, logIndex | The transaction (signature and slot on Solana) |
Resume
With a single wallet, every event carries acursor. After a reconnect, subscribe again with "since": "<cursor of the last event you received>": you receive every trade after it (up to 5 minutes back), then live. Trades you may already have are flagged "replay": true: dedupe them by data.id. If the replay is not available, a REPLAY_TOO_OLD notice gives details.restFromMs: fetch /v1/wallet/trades back to there, the subscription keeps going.
A list subscription takes no since: after a reconnect, subscribe again and read REST for each wallet over the time you were away. See Reconnect & resume.
Billing
1 credit per message delivered: one trade, or one batch of trades. A wallet that does not trade costs nothing, and the connection is free.GET /v1/usage/breakdown reports this channel under WS wallet-trades, where requests is the number of messages delivered.
Errors
| Code | Meaning | What to do |
|---|---|---|
INVALID_PARAM | A parameter was refused. details.param names it (chain, address, wallets[3].address, since) | Fix the subscription |
INVALID_CHAIN | Unknown chain id | Fix the subscription |
RATE_LIMITED | The subscription limit of your account is reached, or the list does not fit in what is left | Close subscriptions, send a shorter list, or ask us to raise the limit |
UPSTREAM_ERROR with details.retryAfterMs | Wallet streams are starting | Send the same subscribe again after details.retryAfterMs |
UPSTREAM_ERROR with details.resumes: true | Live data is temporarily unavailable | Nothing: the subscription resumes by itself |
Close codes
| Code | Meaning |
|---|---|
4401 | Auth - key missing, invalid, or revoked. Live connections are dropped the moment a key is revoked. |
4402 | Monthly credit quota exhausted (the WebSocket mirror of REST 402). |
1012 | Server restart - reconnect after the retryAfterMs of the JSON reason, then subscribe again. |
1013 | Server at capacity - reconnect after the retryAfterMs of the JSON reason. |
1008 | Policy - subscription limits, flooding, or a blocked socket. Fix the cause before reconnecting. |
1001 | Idle timeout - no ping within the keepalive window. |
{
"op": "subscribe",
"channel": "wallet-trades",
"id": "whale-1",
"params": {
"chain": "solana",
"address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj"
}
}
{
"op": "subscribe",
"channel": "wallet-trades",
"id": "followed",
"params": {
"wallets": [
{ "chain": "solana", "address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj" },
{ "chain": "evm:8453", "address": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09" }
]
}
}
{
"op": "subscribed",
"id": "whale-1",
"channel": "wallet-trades",
"updatePeriod": 0
}
{
"op": "event",
"id": "whale-1",
"channel": "wallet-trades",
"data": {
"wallet": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj",
"id": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh:CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump:b",
"at": 1790539767000,
"chain": "solana",
"tokenAddress": "CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump",
"poolAddress": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS",
"isBuy": true,
"amountToken": 15915963.2,
"priceNative": 3.1415e-8,
"volumeNative": 0.5,
"volumeUsd": 75.02,
"feesNative": 0.000105,
"isWash": false,
"isRoutingHop": false,
"txHash": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh",
"block": 371204455,
"logIndex": 0
},
"asOf": 1790539767412,
"cursor": "v1.amun6v2l5lbes.2kx.mfq3c2y2"
}
{
"op": "event",
"id": "followed",
"channel": "wallet-trades",
"data": [
{
"wallet": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09",
"id": "0x9d6dd98095ebcb254576b23b2269edf8fa984b581404209aa2a5fe3a14431bdf:289",
"at": 1790539768000,
"chain": "evm:8453",
"tokenAddress": "0xb2000000000000000000007bf6d5cbb0e24cb301",
"poolAddress": "0x0ca6485b7e9cf814a3fd09d81672b07323535b64",
"isBuy": true,
"amountToken": 77.05662024406023,
"priceNative": 5.4747124708872e-7,
"volumeNative": 0.000042612402192036,
"volumeUsd": 0.08021081608014609,
"feesNative": 0.000000841192,
"isWash": null,
"isRoutingHop": false,
"txHash": "0x9d6dd98095ebcb254576b23b2269edf8fa984b581404209aa2a5fe3a14431bdf",
"block": 49964744,
"logIndex": 289
}
],
"asOf": 1790539768301
}
Messages
{
"op": "subscribed",
"id": "whale-1",
"channel": "wallet-trades",
"updatePeriod": 0
}{
"op": "event",
"id": "whale-1",
"channel": "wallet-trades",
"data": {
"wallet": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj",
"id": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh:CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump:b",
"at": 1790539767000,
"chain": "solana",
"tokenAddress": "CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump",
"poolAddress": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS",
"isBuy": true,
"amountToken": 15915963.2,
"priceNative": 3.1415e-8,
"volumeNative": 0.5,
"volumeUsd": 75.02,
"feesNative": 0.000105,
"isWash": false,
"isRoutingHop": false,
"txHash": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh",
"block": 371204455,
"logIndex": 0
},
"asOf": 1790539767412,
"cursor": "v1.amun6v2l5lbes.2kx.mfq3c2y2"
}{
"op": "subscribe",
"channel": "wallet-trades",
"id": "whale-1",
"params": {
"chain": "solana",
"address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj"
}
}Ack
type:object
Server acknowledgement: the subscription is live.
Trade
type:object
Server push frame, one per trade of a followed wallet (a batch per period with updatePeriod): 1 credit per message.
Subscribe
type:object
Client frame opening the subscription (additive, ack is explicit).