Skip to main content
This endpoint is only available to Growth and Enterprise plans.

Endpoint Details

  • URL: wss://api.mobula.io
  • Event Type: fast-trade

Subscription Formats

The fast-trade endpoint supports subscribing to trades for multiple pools and tokens with real-time updates. Subscribe to multiple pools and tokens using the items array format with assetMode:
{
  "type": "fast-trade",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "assetMode": false,
    "items": [
      {
        "blockchain": "evm:1",
        "address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
      },
      {
        "blockchain": "evm:1",
        "address": "0xA0b86a33E6441e88C5F2712C3E9b74B6F3B5C8b6"
      }
    ],
    "subscriptionTracking": true,
    "maxUpdatesPerMinute": 60
  }
}

Token Mode Subscription

For token-specific trades (when assetMode is true):
{
  "type": "fast-trade",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "assetMode": true,
    "items": [
      {
        "blockchain": "solana",
        "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
      },
      {
        "blockchain": "evm:1",
        "address": "0xA0b86a33E6441e88C5F2712C3E9b74B6F3B5C8b6"
      }
    ],
    "subscriptionTracking": true
  }
}

Parameters

  • assetMode (required): Boolean indicating subscription mode
    • false: Subscribe to pools (default)
    • true: Subscribe to tokens
  • items (required): Array of subscription items, each containing:
    • blockchain (required): Blockchain identifier (e.g., "evm:1", "solana")
    • address (required): Pool or token address
  • subscriptionId (optional): Unique identifier for your WebSocket connection. Auto-generated if not provided
  • subscriptionTracking (optional, default: false): Include subscription details in response logs for debugging
  • maxUpdatesPerMinute (optional): Limit how often the server sends updates for each pool/token. See Update Rate Throttling below
Trade Data Only: This endpoint provides trade events without enriched market data. For complete market statistics with each trade, use market-details or token-details streams instead.Asset Mode: The assetMode parameter determines address interpretation:
  • false (default): Addresses are pool addresses
  • true: Addresses are token addresses

Real-Time Updates

After subscribing, you’ll receive real-time updates whenever new trades occur involving the subscribed pools/tokens.

Real-Time Trade Updates

When trades happen involving subscribed items, you’ll receive updates with trade information. The response format depends on the assetMode used in your subscription:

Pool Mode Response (assetMode: false)

{
  "pair": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640",
  "date": 1704067800000,
  "tokenPrice": 0.0234,
  "tokenPriceVs": 2500.75,
  "tokenAmount": 1000.0,
  "tokenAmountVs": 0.4,
  "tokenAmountUsd": 23.40,
  "tokenNativePrice": 0.00000936,
  "tokenMarketCapUSD": 234000.00,
  "type": "sell",
  "operation": "regular",
  "blockchain": "Ethereum",
  "hash": "0xdef789abc012...",
  "sender": "0x1234567890abcdef...",
  "tokenAmountRaw": "1000000000000000000000",
  "tokenAmountRawVs": "400000000000000000",
  "preBalanceBaseToken": "5000000000000000000000",
  "preBalanceQuoteToken": "2000000000000000000",
  "postBalanceBaseToken": "4000000000000000000000",
  "postBalanceQuoteToken": "2400000000000000000",
  "labels": ["proTrader"],
  "walletMetadata": {
    "entityName": "Wintermute",
    "entityLogo": "https://example.com/wintermute.png",
    "entityLabels": ["market-maker"],
    "entityType": "market_maker",
    "entityDescription": "Wintermute is a leading global algorithmic trading firm",
    "entityTwitter": "https://twitter.com/wintermute_t",
    "entityWebsite": "https://wintermute.com",
    "entityGithub": null,
    "entityDiscord": null,
    "entityTelegram": null
  },
  "platform": "axiom",
  "platformMetadata": {
    "id": "axiom",
    "name": "Axiom",
    "logo": "https://example.com/axiom.png"
  },
  "totalFeesUSD": 0.27,
  "gasFeesUSD": 0.02,
  "platformFeesUSD": 0.23,
  "mevFeesUSD": 0.02,
  "subscriptionId": "sub_abc123",
  "timestamp": 1704067800000
}

Token Mode Response (assetMode: true)

{
  "token": "0xA0b86a33E6441e88C5F2712C3E9b74B6F3B5C8b6",
  "date": 1704067800000,
  "tokenPrice": 0.0234,
  "tokenPriceVs": 2500.75,
  "tokenAmount": 1000.0,
  "tokenAmountVs": 0.4,
  "tokenAmountUsd": 23.40,
  "tokenNativePrice": 0.00000936,
  "tokenMarketCapUSD": 234000.00,
  "type": "sell",
  "operation": "regular",
  "blockchain": "Ethereum",
  "hash": "0xdef789abc012...",
  "sender": "0x1234567890abcdef...",
  "tokenAmountRaw": "1000000000000000000000",
  "tokenAmountRawVs": "400000000000000000",
  "preBalanceBaseToken": "5000000000000000000000",
  "preBalanceQuoteToken": "2000000000000000000",
  "postBalanceBaseToken": "4000000000000000000000",
  "postBalanceQuoteToken": "2400000000000000000",
  "labels": ["sniper", "freshTrader"],
  "walletMetadata": null,
  "platform": null,
  "platformMetadata": null,
  "totalFeesUSD": 0.27,
  "gasFeesUSD": 0.02,
  "platformFeesUSD": 0.23,
  "mevFeesUSD": 0.02,
  "subscriptionId": "sub_abc123",
  "timestamp": 1704067800000
}

Response Fields

  • pair: Pool address where the trade occurred (only in pool mode: assetMode = false)
  • token: Base token address involved in the trade (only in token mode: assetMode = true)
  • date: Timestamp of the trade (Unix milliseconds)
  • tokenPrice: Price of the traded token in USD
  • tokenPriceVs: Price of the quote token in USD
  • tokenAmount: Amount of tokens traded (base token)
  • tokenAmountVs: Amount of quote tokens traded
  • tokenAmountUsd: USD value of the trade
  • tokenNativePrice: Price of the traded token in the blockchain’s native currency (e.g., ETH for Ethereum, SOL for Solana)
  • tokenMarketCapUSD: Market capitalization of the traded token in USD (based on circulating supply)
  • type: Trade type (“buy” or “sell”)
  • operation: Operation type (“regular”, “arbitrage”, etc.)
  • blockchain: Blockchain name
  • hash: Transaction hash
  • sender: Transaction sender address
  • tokenAmountRaw: Raw token amount (base token)
  • tokenAmountRawVs: Raw token amount (quote token)
  • preBalanceBaseToken: Sender’s balance of the base token before the swap (bigint or null)
  • preBalanceQuoteToken: Sender’s balance of the quote token before the swap (bigint or null)
  • postBalanceBaseToken: Sender’s balance of the base token after the swap (bigint or null)
  • postBalanceQuoteToken: Sender’s balance of the quote token after the swap (bigint or null)
  • labels: Array of labels associated with the sender wallet for the base token/pool (see Label Values below)
  • walletMetadata: Entity metadata for the sender wallet (see Wallet Metadata below), or null if not available
  • platform: Trading platform/aggregator identifier (e.g., “axiom”, “gmgn”, “padre”, “trojan”, “universalX”) or null if not available
  • platformMetadata: Object with id, name, and logo for the trading platform, or null if not available
  • subscriptionId: Your subscription identifier
  • timestamp: Server timestamp when the update was sent

Fee Breakdown

Complete fee transparency: Unlike other platforms that only show gas + total, Mobula provides the full breakdown in real-time.
  • totalFeesUSD: Total fees in USD (gas + platform + MEV combined)
  • gasFeesUSD: Network gas fees in USD
  • platformFeesUSD: Platform/aggregator fees in USD (Axiom, GMGN, Trojan, etc.)
  • mevFeesUSD: MEV-related fees in USD (priority fees, Jito bundles, etc.)

Label Values

The labels array can contain any combination of the following values, providing insight into the trader’s behavior and classification:
LabelValueDescription
SnipersniperWallet that bought the token very early (typically in the first few blocks after launch)
InsiderinsiderWallet with suspected insider/privileged information (e.g., pre-launch access)
BundlerbundlerWallet that bundles multiple transactions together (often associated with MEV strategies)
Pro TraderproTraderUses a known professional trading platform (Axiom, GMGN, Trojan, Padre, UniversalX, etc.)
Smart TradersmartTraderWallet identified as a profitable/smart trader within the last 7 days
Fresh TraderfreshTraderNewly funded wallet (received initial funding within the last 24 hours)
DevdevToken deployer/developer wallet
Liquidity PoolliquidityPoolAddress is a liquidity pool
Label Context: Labels are scoped to the specific token being traded. For example, a wallet may be labeled as sniper for Token A but not for Token B.

Example with Labels

{
  "token": "0xA0b86a33E6441e88C5F2712C3E9b74B6F3B5C8b6",
  "type": "buy",
  "tokenAmountUsd": 5000.00,
  "sender": "0x1234567890abcdef...",
  "labels": ["sniper", "proTrader", "smartTrader"],
  "platform": "axiom",
  "hash": "0xdef789abc012..."
}
In this example, the trader:
  • Sniped the token early (sniper)
  • Uses a professional trading platform (proTrader)
  • Has been identified as a smart/profitable trader (smartTrader)

Wallet Metadata

When the sender wallet is a known entity (e.g., Wintermute, Binance, Jump Trading), the walletMetadata field provides additional context:
FieldTypeDescription
entityNamestring | nullEntity name (e.g., “Wintermute”)
entityLogostring | nullURL to the entity’s logo
entityLabelsstring[]Array of entity classification labels (e.g., “market-maker”)
entityTypestring | nullEntity type classification
entityDescriptionstring | nullShort description of the entity
entityTwitterstring | nullTwitter/X URL
entityWebsitestring | nullWebsite URL
entityGithubstring | nullGitHub URL
entityDiscordstring | nullDiscord invite URL
entityTelegramstring | nullTelegram URL

Optional Fields Behavior

Some fields may be entirely absent, not null: In streams that use the buildSwapMessage format (token-details, market-details, pair), the labels and walletMetadata fields are conditionally included — when there is no data, the field is completely omitted from the JSON payload rather than being set to null or an empty array.In fast-trade streams, labels and walletMetadata are always present (as [] and null respectively when empty).Always use optional chaining or check for field existence:
const labels = data.labels ?? [];
const entityName = data.walletMetadata?.entityName ?? null;

Unsubscribing from the Stream

Unsubscribe from All Trade Streams

{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "type": "fast-trade"
  }
}

Unsubscribe from Specific Subscription

{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "subscriptionId": "sub_abc123"
  }
}

Unsubscribe from Specific Subscription with Type

{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "type": "fast-trade",
    "subscriptionId": "sub_abc123"
  }
}

Unsubscribe from Specific Items (Partial Unsubscription)

You can unsubscribe from specific pools/tokens while keeping others active in the same subscription:
{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "type": "fast-trade",
    "items": [
      {
        "blockchain": "evm:1",
        "address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
      }
    ]
  }
}

Unsubscribe from Multiple Specific Items

{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "type": "fast-trade",
    "items": [
      {
        "blockchain": "evm:1",
        "address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
      },
      {
        "blockchain": "evm:1",
        "address": "0xA0b86a33E6441e88C5F2712C3E9b74B6F3B5C8b6"
      }
    ]
  }
}

Unsubscribe from Specific Items in a Specific Subscription

{
  "type": "unsubscribe",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "type": "fast-trade",
    "subscriptionId": "sub_abc123",
    "items": [
      {
        "blockchain": "evm:1",
        "address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
      }
    ]
  }
}
If you didn’t provide a subscriptionId when subscribing, one is auto-generated. To retrieve it, set "subscriptionTracking": true in the subscription payload.For partial unsubscriptions without subscriptionId, the system will automatically find and modify subscriptions that contain the specified items, leaving other items in those subscriptions active.

Update Rate Throttling

You can control how frequently the server sends update messages per pool/token using the maxUpdatesPerMinute field. This is useful for reducing bandwidth when you don’t need every single trade update.
{
  "type": "fast-trade",
  "authorization": "YOUR-API-KEY",
  "payload": {
    "assetMode": false,
    "items": [
      {
        "blockchain": "evm:1",
        "address": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
      }
    ],
    "maxUpdatesPerMinute": 60
  }
}

How It Works

Despite the name, maxUpdatesPerMinute does not set a budget that gets consumed over a minute. Instead, it sets a minimum interval between delivered updates per pool/token:
interval = 60 000ms / maxUpdatesPerMinute
For example, maxUpdatesPerMinute: 100 → minimum interval of 600ms between two delivered updates for the same pool/token.
  • Interval-based, not budget-based: The server enforces a cooldown between updates. Once an update is delivered, all subsequent updates for that pool/token are dropped until the interval elapses. There is no counter that depletes — after each delivered update, the cooldown simply restarts.
  • Per-pool/per-token throttle: Each subscribed item is throttled independently. Subscribing to 5 items with maxUpdatesPerMinute: 60 means each item sends at most 1 update/second.
  • Dropped, not buffered: When an update arrives during the cooldown, it is silently dropped — not queued or aggregated. The next update arriving after the interval has elapsed will be delivered normally.

Burst Behavior Example

With maxUpdatesPerMinute: 100 (interval = 600ms), if a pool receives a burst of 50 updates in 1 second:
TimeEventResult
t=0msUpdate 1 arrivesDelivered (cooldown starts)
t=50msUpdates 2–10 arriveDropped (still within 600ms cooldown)
t=600msUpdate ~20 arrivesDelivered (cooldown elapsed, restarts)
t=800msUpdates ~25–50 arriveDropped (still within new 600ms cooldown)
t=2sNext update arrivesDelivered normally
You receive ~2 updates from the burst, and updates resume normally afterwards. There is no debt or penalty — the throttle does not “remember” dropped updates or block future delivery.

Reference Values

maxUpdatesPerMinuteEffective intervalDescription
600100msMaximum rate (~10 updates/sec per item)
601sOne update per second per item
610sOne update every 10 seconds
160sOne update per minute (minimum rate)
When maxUpdatesPerMinute is not provided, no throttle is applied and updates are delivered as fast as they arrive.

Implementation Example

const socket = new WebSocket("wss://api.mobula.io");

socket.addEventListener("open", () => {
  socket.send(JSON.stringify({
    type: "fast-trade",
    authorization: "YOUR_API_KEY",
    payload: {
      assetMode: false,
      items: [
        {
          blockchain: "evm:1",
          address: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
        }
      ],
      subscriptionTracking: true
    }
  }));
});

socket.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  
  // Process trade update
  console.log(`${data.type} trade:`, data);
  console.log(`Amount: $${data.tokenAmountUsd}`);
});

socket.addEventListener("error", (error) => {
  console.error("WebSocket error:", error);
});

socket.addEventListener("close", () => {
  console.log("WebSocket connection closed");
});
You can use the Network tab in your browser to see the WebSocket requests and responses in real-time.

Connection Keepalive (Ping/Pong)

To maintain active WebSocket connections and prevent timeouts, you can use the ping/pong mechanism: Send ping:
{"event":"ping"}
Receive pong: The server will respond with a pong message to confirm the connection is active.
Use ping messages periodically (every 30-60 seconds) to keep long-lived connections alive.

Support

Can’t find what you’re looking for? Reach out to us, response times < 1h.

Support

Telegram

Support

Slack

Need help?

Email