The pump.fun WebSocket API: stream every trade, new coin and callout as it happens

Stream pump.fun trades on Solana and 11 EVM chains, new coins, callouts and fomo.family traders over one WebSocket. Channels, filters and Node and Python code.

7 min read

The pump.fun WebSocket API: live trades, new coins and callouts
On this page
  1. What you can stream
  2. Should you read the chain yourself instead?
  3. Connecting
  4. A Node.js client that stays up
  5. The same in Python
  6. What the messages look like
  7. Filters that matter
  8. Replay, and why you will want it
  9. Keeping a client healthy
  10. Three things people build with it
  11. Frequently asked questions
  12. Where to go next

Polling is the wrong tool for pump.fun. A coin can launch, run 10x and die between two requests, and a trader you follow can buy and sell inside a minute. If you need to see things as they happen, you need a pump.fun WebSocket: one connection that pushes each event the moment it exists.

pump.fun has no public WebSocket for developers. Its apps use live feeds of their own, but those are internal, like the rest of its API. This guide covers the stream we run at wss://api.pumpfomo.com/v1/stream: what it carries, how to connect and filter, the messages you get, and how to keep a client alive for weeks. The code is in Node.js and Python.

What you can stream

One connection, five channels. Subscribe to any mix of them.

Channel What arrives Filters
trades Every pump.fun trade on Solana and 11 EVM chains, with the trader when we know the wallet coins (up to 1,000), wallets (up to 1,000), chains, side, minimum USD
traders The trades of people you choose: pump.fun users (every wallet we know for them) and fomo.family traders by handle pump.fun ids or wallets (up to 1,000), fomo handles (up to 100), chains, side
coins New pump.fun coins as they are created none
callouts pump.fun callouts as they are posted, with author, thesis and market cap at the call coins
fomo fomo.family trades and theses, and optionally fomo's global feed handles, tokens, alerts

The trades channel covers Solana plus Base, BNB Chain, Ethereum, Robinhood Chain, Monad, Arc, X Layer, MegaETH, Polygon, Ink and HyperEVM. At busy times that is a few hundred trades a second, so you usually filter it.

Should you read the chain yourself instead?

You can, and for some products you should. A Solana RPC node or a Geyser plugin will hand you every transaction of pump.fun's programs with the lowest latency you can get. Be clear about what that means in practice:

  • You parse each program yourself: the bonding curve, PumpSwap, and the other launchpads pump.fun lists. Then you do it again for each EVM chain.
  • You get addresses, not people. Nothing on-chain says a wallet belongs to a trader with a following, or that a buy came with a callout.
  • You run the infrastructure: nodes, reconnects, backfills after gaps.

If you are building a sniper that lives or dies on milliseconds, run your own node. If you are building something about people (alerts on traders, a social feed, copy-trading signals, dashboards), a stream that already joins trades to traders saves you most of the work.

Connecting

The URL is wss://api.pumpfomo.com/v1/stream. Authenticate with a key that has the stream scope:

  • From a server: Authorization: Bearer <key> (or X-API-Key) on the upgrade request.
  • From a browser, which can't set headers on a WebSocket: ?key=<key> in the URL. Only do this with a key limited to the stream scope and your IPs.

Try it in a terminal first with websocat or wscat:

bash
wscat -c wss://api.pumpfomo.com/v1/stream -H "Authorization: Bearer $PUMPFOMO_KEY"
> {"op":"subscribe","channel":"trades","minUsd":5000}

The first message is a welcome with your connection id and how many streams your plan allows. After a subscribe you get subscribed, which echoes what your filter resolved to, and then events.

Plans and cost

Streams come with the plan: there is no charge by the minute or by the message, however much a connection carries. The plan sets how many connections you can hold at once: Builder 1, Growth 5, Scale 15. Free and Starter have no streams.

A Node.js client that stays up

This client subscribes, reconnects with backoff and resubscribes after every reconnect. It uses the ws package, which answers the server's pings for you.

js
import WebSocket from "ws"

const URL = "wss://api.pumpfomo.com/v1/stream"
const SUBSCRIPTIONS = [
  { op: "subscribe", channel: "trades", minUsd: 5000, side: "buy" },
  { op: "subscribe", channel: "coins", replay: false },
]

const seen = new Set() // tx ids, so a replay after a reconnect isn't handled twice
let attempt = 0

function connect() {
  const ws = new WebSocket(URL, {
    headers: { Authorization: `Bearer ${process.env.PUMPFOMO_KEY}` },
  })

  ws.on("open", () => {
    attempt = 0
    for (const s of SUBSCRIPTIONS) ws.send(JSON.stringify(s))
  })

  ws.on("message", (raw) => {
    const msg = JSON.parse(raw)
    switch (msg.type) {
      case "trade":
        if (seen.has(msg.tx)) return
        seen.add(msg.tx)
        if (seen.size > 50_000) seen.clear()
        console.log(
          `${msg.chain.padEnd(9)} ${msg.side.toUpperCase().padEnd(4)} $${Math.round(msg.amountUsd)}`,
          msg.mint,
          msg.trader ? `by ${msg.trader.handle ?? msg.trader.displayName}` : "",
        )
        break
      case "coin":
        console.log(`NEW ${msg.symbol} (${msg.name}) on ${msg.chain} by ${msg.creator}`)
        break
      case "error":
        console.error("stream error:", msg)
        break
    }
  })

  ws.on("close", (code) => {
    if (code === 4002) return console.error("out of credits")
    if (code === 4003) return console.error("no free stream slot on this plan")
    const delay = Math.min(30_000, 1000 * 2 ** attempt++)
    console.warn(`closed (${code}), reconnecting in ${delay} ms`)
    setTimeout(connect, delay)
  })

  ws.on("error", (err) => console.error(err.message))
}

connect()

The same in Python

python
import asyncio
import json
import os

import websockets

URL = "wss://api.pumpfomo.com/v1/stream"
HEADERS = {"Authorization": f"Bearer {os.environ['PUMPFOMO_KEY']}"}

async def run():
    delay = 1
    while True:
        try:
            async with websockets.connect(URL, additional_headers=HEADERS) as ws:
                delay = 1
                await ws.send(json.dumps({"op": "subscribe", "channel": "callouts"}))
                async for raw in ws:
                    msg = json.loads(raw)
                    if msg["type"] == "callout":
                        c = msg["callout"]["callout"]
                        print(f"{c['userName']} called {msg['mint']} at ${msg['calledOutAtMcap']:,.0f}: {c['thesis']!r}")
                    elif msg["type"] == "replay":
                        print(f"replay: {len(msg['events'])} recent {msg['kind']} events")
        except websockets.ConnectionClosed as e:
            if e.code in (4002, 4003):
                raise
        except OSError:
            pass
        await asyncio.sleep(delay)
        delay = min(delay * 2, 30)

asyncio.run(run())

websockets 13 and later take additional_headers. Older versions call it extra_headers.

What the messages look like

A trade, from a real Robinhood Chain buy:

json
{
  "type": "trade",
  "platform": "pump",
  "chain": "robinhood",
  "mint": "0x898588e7d2b77527476bbc877fc73bc49fcec188",
  "tx": "0xbd9acdda89c8ee40e887a90d35093757804e97ad191f8a4dc706187a92320f1a",
  "side": "buy",
  "wallet": "0x204faca1764b154221e35c0d20abb3c525710498",
  "amountUsd": 1063.24,
  "amountNative": 0.455,
  "baseAmount": 1149437.38,
  "priceUsd": 0.000946,
  "marketCapUsd": 946407.66,
  "protocol": "UNISWAP_V4",
  "pool": "0x722fb6eac3ec7bd0f27bbd7f99ccb0ed886840c749b30377863c5f75b25569ae",
  "ts": 1792969931000
}

When the wallet belongs to someone in our index, the trade also carries trader with platform, userId, handle, displayName and avatar. ts is Unix milliseconds and EVM addresses are lower-case.

A coin message has mint, name, symbol, creator, bonding_curve, metadata_uri, market_cap (a decimal string), program, chain and launchpad. pump.fun's own feed includes coins from other launchpads, so check launchpad if you only want coins made on pump.fun.

A callout has calloutId, mint, chain, calledOutAtMcap, costBasisUsd and pump.fun's full record under callout.callout: the thesis, the author's name and picture, and the price at the call.

A fomo_trade has kind (buy, sell or thesis), amountUsd, priceUsd, marketCapUsd, a token object and the trader with their fomo handle.

Filters that matter

  • The firehose needs a floor. A trades subscription with no coins and no wallets must set minUsd to 1,000 or more. With coins or wallets you can go as low as you like.
  • One filter per channel. Sending a new subscribe for a channel replaces its filter. To watch more coins, send the full list again.
  • traders is separate from trades. Changing who you follow doesn't touch your coin filters, and the other way round. Unknown ids and handles come back in pumpNotFound and fomoNotFound, so you can fix typos.
  • Limits: 1,000 coins, 1,000 wallets, 1,000 pump.fun traders and 100 fomo traders per connection. You can send at most 10 messages a second (bursts of 20), and each message can be up to 64 KB.

Replay, and why you will want it

Right after a subscribe to coins, callouts, fomo or the fomo side of traders, you get a replay message. It holds up to 50 of the latest matching events, oldest first. After a reconnect, that fills the gap you missed while you were away. Deduplicate by tx (trades), mint (coins), calloutId (callouts) or id (fomo events). Send "replay": false if you don't want it.

Keeping a client healthy

  • The server sends a WebSocket ping every 25 seconds. A client that doesn't answer within 10 seconds is closed. Most libraries answer pings automatically. If yours doesn't, send {"op":"ping"} and you'll get a pong.
  • The server keeps a queue of 4,096 messages per connection. If you read too slowly, it closes the connection with code 4008. Fix it by filtering harder or by handing messages to a queue instead of processing them inline.
  • 4002 means you're out of credits, and 4003 means your plan's streams are all in use. Reconnecting won't help with either, so stop and alert.
  • Always resubscribe after a reconnect. Subscriptions belong to the connection, not to your key.

Three things people build with it

Whale alerts to Telegram. Subscribe to trades with minUsd: 10000 and side: "buy", then post each message to a Telegram chat through the Bot API. Add the trader's handle when the message has one. Big buys from known traders are the signal people actually care about.

A new-coin radar with context. Subscribe to coins. For each new mint, look up the creator with /v1/pump/users/{creator} and their earlier launches with /v1/pump/users/{wallet}/created-coins. A creator with 40 dead coins is a very different signal from a known trader's first launch.

Following people, not wallets. Subscribe to traders with pump.fun user ids and fomo handles. On pump.fun we follow every wallet we know for each person, so a trader switching wallets doesn't break your feed. On fomo.family, trades come from fomo's own data by handle, which matters because fomo profile addresses aren't the wallets that trade.

Frequently asked questions

Does pump.fun have an official WebSocket API?

pump.fun doesn't offer a public, documented WebSocket for developers. Its apps use internal live feeds. pumpfomo's stream delivers pump.fun trades, new coins and callouts over one documented WebSocket with an API key.

How many messages does the pump.fun trade stream send?

The full trade flow across Solana and the EVM chains runs at a few hundred trades a second at busy times. That's why the unfiltered firehose is limited to trades of $1,000 or more. Filter by coins or wallets to receive smaller trades.

Is the pump.fun WebSocket free?

Streams need a paid plan, starting with Builder at $149 a month, which includes one connection. There is no charge by the minute or the message on top.

Can I stream one wallet's pump.fun trades?

Yes. Subscribe to trades with wallets: [...] (up to 1,000), or to traders with pump.fun user ids to follow every wallet a person uses.

Does the stream include pump.fun coins on Base, BNB Chain and other EVM chains?

Yes. The trades channel carries pump.fun trades on Solana and 11 EVM chains. Use chains to limit it, for example ["solana", "base"].

Can I stream fomo.family trades too?

Yes. The traders channel takes fomo handles (up to 100), and the fomo channel carries fomo trades, theses and, with alerts: true, fomo's global feed.

Where to go next

Try it on real data, free.

10,000 credits a month, wallet or Telegram sign-in, no card. Every endpoint in these guides works on the Free plan; streams start at Builder.

More guides