DocsAPI

Live streams

Subscribe to live trades, live PnL and live wallet balances over a WebSocket with your API key.

Connect to wss://evm.vortexdeployer.com/evm/ws and send JSON messages. Put your key in token on each subscribe.

const ws = new WebSocket('wss://evm.vortexdeployer.com/evm/ws');
ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'subscribe', topic: 'txs', token: 'vd_…' }));
  setInterval(() => ws.send(JSON.stringify({ type: 'ping' })), 25_000);
};
ws.onmessage = (m) => console.log(JSON.parse(m.data));
Server-side only

Never open a keyed stream from a web page. Anyone can read the key from the browser.

Topics#

TopicScopeSends
txsstreamEvery trade the platform sees, as it happens — across every venue. No per-token subscribe needed
txs:<mint>streamTrades on one token, starting with a snapshot of its recent trades
pnlstreamYour per-token PnL on Solana, refreshed as it changes
pnl:<mint>streamOne token's PnL for your account
wallet:<address>streamLive balance of one of your wallets: a snapshot, then a frame on every change
tasksreadYour running tasks, then every change

After a subscribe you get { "type": "subscribed", "topic": … }, or { "type": "error", "topic": …, "message": … } saying why not. Send { "type": "unsubscribe", "topic": … } to stop a topic.

The bare txs topic is a firehose: subscribe once and every trade streams in, no mint list to keep. It answers with { "type": "txs_snapshot", "topic": "txs", "note": "firehose: deltas only" }, then live frames. txs:<mint> instead opens with a trade_snapshot of that token's recent trades.

Trade frames#

Every trade frame carries both sides of the pair, the pool, and the pool's reserves before and after the swap.

Frames keep their on-chain names

Stream frames are the platform's raw chain feed and keep snake_case names (pool_address, base_amount, block_index). Only REST answers are camelCase.

{
  "type": "trade",
  "chain": "solana",
  "mint": "NnLz6wXfB3c41KwPWPvk9Rz75zR5enTGtYmsELrpump",
  "quote_mint": "So11111111111111111111111111111111111111112",
  "pool_address": "B8GeyGLChfj3Mn9HCyVJYS4nMRSMVDCCutRTwGasoH7V",
  "dex": "pump_swap",
  "side": "buy",
  "trader": "A2uqWi4Zm3yVYqvuRb4GF6BSb56pocvw1J2V2nQeU3QE",
  "base_amount": "44917",
  "quote_amount": "179054",
  "signature": "42RU7t2Drzyr…faT22",
  "block": 447482805,
  "block_index": 805,
  "timestamp": 1789549114,
  "pre_base_reserves": "2105102154648",
  "pre_quote_reserves": "8391614579937",
  "post_base_reserves": "2105102109731",
  "post_quote_reserves": "8391614758991"
}
Field
mintThe token traded (the base token)
quote_mintThe token it traded against (the quote token — e.g. wrapped SOL)
pool_addressThe pool the trade went through
dexThe venue (pump_fun, pump_swap, raydium_cpmm, meteora_bonding, pons, …)
sidebuy or sell
traderThe wallet that traded
base_amount, quote_amountAmounts traded, in each token's base units
signature, block, block_index, timestampWhere the trade landed on chain
pre_base_reserves, pre_quote_reservesThe pool's two reserves just before the swap
post_base_reserves, post_quote_reservesThe pool's two reserves just after

Reserves are null for a venue that does not report them. From the reserves you can read the pool's price without another call.

PnL frames#

{ "type": "pnl_update", "mint": "7xKX…pump", "at": 1757923203112, "pnl": { } }
  • at only ever goes up. Ignore a frame whose at is not newer than the last one.
  • On pnl (no mint), the frame carries chain and tokens instead of pnl.
  • pnl: null comes with a reason.
  • { "type": "resync" } means the server may have missed updates: re-read what you need over REST.

Balance frames#

wallet:<address> streams the live coin and token balance of one wallet. The address must be one of your wallets — any other address is refused. Subscribing answers with a wallet_balance_snapshot, then a wallet_balance_update on every change:

{
  "type": "wallet_balance_snapshot",
  "topic": "wallet:7tXi4mbvppPBgYgTVj2NpYq9K1KYYQvHv6tfCpJv9kMT",
  "chain": "solana",
  "address": "7tXi4mbvppPBgYgTVj2NpYq9K1KYYQvHv6tfCpJv9kMT",
  "sol": "419434195",
  "tokens": [ { "mint": "7xKX…pump", "amount": "3512000000" } ],
  "block": 447482145,
  "block_index": null
}
{
  "type": "wallet_balance_update",
  "chain": "solana",
  "address": "7tXi4mbvppPBgYgTVj2NpYq9K1KYYQvHv6tfCpJv9kMT",
  "sol": "420100000",
  "tokens": [ { "mint": "7xKX…pump", "amount": "3500000000" } ],
  "block": 447482806,
  "block_index": 806
}
Field
chain, addressThe wallet
solCoin balance in the smallest unit as a string — lamports on Solana, wei on EVM
tokensToken balances being tracked for this wallet: mint and amount in base units
block, block_indexWhere the balance was last observed on chain (block_index can be null)

To seed a token into the snapshot, send mint on the subscribe: { "type": "subscribe", "topic": "wallet:<address>", "mint": "7xKX…pump", "token": "vd_…" }. The stream then keeps that token's amount live alongside the coin balance.

A key limited to an allowed wallet list can only open wallets on that list.

Rules#

  • One identity per socket. Once a socket subscribes with a key, a different key or account on the same socket is refused.
  • Up to 5 sockets per key, and 50 txs/pnl subscriptions (and 50 wallet subscriptions) per socket.
  • Too many bad keys closes the socket (code 4008).
  • Revoking or editing the key closes its sockets (code 4001). Reconnect with a valid key.
  • Keys can't use the socket's read requests. Use REST for reads.
  • The key's IP allowlist applies to sockets too.

Reconnect with a backoff after a drop, then subscribe again. Subscriptions don't survive a reconnect.

See also#