Real-time vs HTTP
GET Method
Available in HTTP queriesUse the same filtering system in HTTP GET requests for simple queries.
POST Method
Available in HTTP queriesUse the same filtering system in HTTP POST requests for advanced configurations.
Overview
The Holders Stream provides real-time position tracking for token holders. It tracks holder positions directly from swap events and periodically resyncs from the database for accuracy.Protocol
| Message | Description |
|---|---|
init | Full snapshot of top 100 holders on subscribe |
update | Single holder position changed (balance, PnL, volume) |
sync | Periodic full resync from DB every 30s |
Endpoint Details
- URL:
wss://api.mobula.io - Event Type:
holders
Subscription
Multiple Tokens
Parameters
tokens(required): Array of token subscription items, each containing:address(required): Token addressblockchain(required): Blockchain identifier (e.g.,"Solana","evm:8453")
sortBy(optional, default:"balance"): Controls how the top 100 holders are sorted. Accepts"balance"(sort by USD balance descending) or"realizedPnl"(sort by realized PnL descending). Use"realizedPnl"for a top traders viewsubscriptionId(optional): Unique identifier for your WebSocket connection. Auto-generated if not providedsubscriptionTracking(optional, default:false): Include subscription details in response logs for debugging
Maximum 10 tokens per connection for optimal performance.
Message Types
init — Full snapshot on subscribe
Sent once when you subscribe. Contains the top 100 holders sorted by the sortBy criteria (balance by default, or realized PnL):
update — Single holder changed
Sent in real-time when a swap changes a holder’s position. Both the buyer and seller are updated:
update message is sent with tokenAmount: "0". The client should remove this holder from its list.
sync — Periodic full resync
Sent every 30 seconds with a fresh snapshot from the database (same format as init). Use this to reconcile any missed updates or drift:
Data Model
Each holder object contains the following fields:| Field | Type | Description |
|---|---|---|
walletAddress | string | Wallet address |
tokenAddress | string | Token contract address |
chainId | string | Chain identifier (e.g., solana:mainnet, evm:1) |
tokenAmount | string | Current token balance (formatted) |
tokenAmountRaw | string | Raw token balance (with decimals) |
tokenAmountUSD | string | Current balance value in USD |
percentageOfTotalSupply | string | Percentage of total supply held |
buys | number | Total buy transactions |
sells | number | Total sell transactions |
volumeBuyUSD | string | Total buy volume in USD |
volumeSellUSD | string | Total sell volume in USD |
volumeBuyToken | string | Total buy volume in token units |
volumeSellToken | string | Total sell volume in token units |
avgBuyPriceUSD | string | Average buy price in USD |
avgSellPriceUSD | string | Average sell price in USD |
totalBoughtTokens | string | Total tokens bought |
totalSoldTokens | string | Total tokens sold |
totalBoughtUSD | string | Total USD spent buying |
totalSoldUSD | string | Total USD received selling |
realizedPnlUSD | string | Realized profit/loss in USD |
unrealizedPnlUSD | string | Unrealized profit/loss in USD |
totalPnlUSD | string | Total PnL (realized + unrealized) |
isLiquidityPool | boolean | Whether this address is a liquidity pool |
labels | string[] | Wallet tags (e.g., insider, bundler, sniper, dev, LP) |
walletFundAt | string | null | When the wallet was first funded |
lastActivityAt | string | null | Last activity timestamp |
firstTradeAt | string | null | First trade timestamp for this token |
lastTradeAt | string | null | Last trade timestamp for this token |
platform | object | null | Trading platform used (see below) |
walletMetadata | object | null | Entity metadata from wallet labeling (see below) |
fundingInfo | object | Wallet funding source details (see below) |
platform
Trading platform the wallet used (e.g., Photon, BullX, Maestro):
walletMetadata
Entity information from wallet labeling:
fundingInfo
Where the wallet’s initial funds came from:
Client Implementation
Key Features
- Trades-based tracking — Positions are updated from swap events in real-time, not from external services
- LP positions included — Liquidity pool addresses are tracked and updated with
isLiquidityPool: true - Both sides updated — On each swap, both the buyer (recipient) and seller (sender) positions are updated
- Post-balance accuracy — Uses on-chain post-balance from the swap for exact balance tracking
- Periodic resync — Automatic
syncfrom DB every 30s ensures consistency - Capped at 100 — Init and sync return top 100 holders, sorted by balance (default) or realized PnL via
sortBy
Connection Keepalive (Ping/Pong)
To maintain active WebSocket connections and prevent timeouts: Send ping:Unsubscribe
Unsubscribe from all holder streams
Unsubscribe from specific subscription
Support
Need help? Our response times are < 1h.Support
Telegram
Support
Slack
Need help?
Email