Stream guide

pumpapi signal stream

The pumpapi WebSocket streams live pump.fun signal and market data — arms, graduations, whale moves, trades and candles — delivered within milliseconds of detection. There is no anonymous or free tier — every connection requires an API key backed by an active paid subscription.

Endpoint wss://pumpws.bubudev.win/connection/websocket · Auth required — subscription API key in connect data.apikey · Protocol Centrifugo (WebSocket, RFC 6455)

Quick start

Connect and receive events in under 10 lines (npm i centrifuge):

JavaScript
import { Centrifuge } from "centrifuge";

const client = new Centrifuge("wss://pumpws.bubudev.win/connection/websocket", {
  data: { apikey: "<YOUR_PUMP_API_KEY>" }, // pump_… from the dashboard
});

client.connect();
client.subscribe("marketdata", ({ data }) => {
  console.log(data.kind, data.mint, data.payload);
});

No SDK? Talk the raw protocol directly — e.g. with websocat:

Raw WebSocket JSON
websocat "wss://pumpws.bubudev.win/connection/websocket?format=json"
# then send (one JSON frame per line):
{"id":1,"connect":{"data":{"apikey":"pump_…"}}}
{"id":2,"subscribe":{"channel":"marketdata"}}

Authentication

  1. Open the dashboard, sign in, pick a plan and press Pay — you get a one-time SOL deposit address (valid 24h).
  2. Send the exact amount (0.5 / 1.5 / 4 SOL). The monitor confirms on-chain within ~30 seconds and issues your key.
  3. The key appears under Centrifugo API key on the dashboard — pass it as data.apikey when connecting (snippet above).
Enforcement is server-side: anonymous connects are rejected, and every subscribe re-checks your subscription. Weekly keys get signals only — market data needs monthly or higher. When your subscription lapses (after the 24h grace), the server disconnects active sessions automatically. Treat the key like a password; wrong payment amounts are logged, not credited. Renewals and coupons never change it — if it leaks, use Rotate key on the dashboard: the old key dies immediately, open sessions are disconnected, and every key you ever issued stays in your key history.

Channels

ChannelContainsTier
signalsEvery signal: arms, graduations, migrations, whale moves, milestonesAny tier
signals:mint:<mint>Signals for one token mint (base58)Any tier
marketdataTrades, migrations, live/closed candlesMonthly +
marketdata:mint:<mint>Market data for one tokenMonthly +

Any tier = weekly, monthly or quarterly — no subscription, no access. Subscribe to the firehose, or to :mint:<mint> lanes to receive a single token only.

Message envelope

Every publication is a versioned JSON envelope. payload carries the signal metadata verbatim — full examples for each kind below.

Envelope v1
{
  "v": 1,                    // envelope schema version
  "id": "0f5c9a3e-…",        // unique id — dedupe / trace across consumers
  "kind": "arm",             // signal type — switch on this
  "ts": 1756915200000,       // event time (ms since epoch)
  "wallTs": 1756915200123,   // server receive time (ms)
  "mint": "5hBz…",           // token mint address (when known)
  "payload": { … }           // full signal metadata — see examples below
}

Payload · marketdata

The 3 kinds published to marketdata. Trades, migrations and candles — monthly tier and up. All amounts are SOL-denominated. Fields with no value are omitted — code against undefined.

market.trade

Every pump + pump-amm trade from the firehose, enriched with pool and pricing context. This is the raw feed the candles are built from.

Example event
{
  "v": 1,
  "id": "8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e",
  "kind": "market.trade",
  "ts": 1756915700000,       // trade time (payload.timestamp) or server time
  "wallTs": 1756915700123,
  "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
  "payload": {
    "kind": "market.trade",
    "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
    "symbol": "BUBU",
    "action": "buy",         // "buy" | "sell"
    "marketCapQuote": 142.6, // market cap in QUOTE-TOKEN units — SOL while the
                             // quote is WSOL; USDC/USDT/USD1/stock pairs report
                             // raw quote units (#321). The OHLC basis for candles.
    "quoteAmount": 3.2,      // this trade's volume in quote-token units (absolute)
    "timestamp": 1756915700000, // trade time (ms)
    "pool": "6Pq8mYcVdRnZ2wXjKfTgH4sLbAeNu7QrYcUvWxZ1p2o", // AMM pool address (post-migration)
    "poolCreatedBy": "Gk2mNvBx7QrYcUdAeBsFgHjKlMnOpQrStUvWz3", // pool creator pubkey
    "signature": "5XyzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvWz", // tx signature — dedupe key
    "txSigner": "Gk2mNvBx7QrYcUdAeBsFgHjKlMnOpQrStUvWz3", // tx signer pubkey
    "mayhemMode": false,     // pump.fun mayhem-mode flag on the trade
    "price": 0.00000021,     // trade price
    "tokenAmount": 15200000, // token amount moved in this trade
    "tokensInPool": 793400000, // token side of pool reserves
    "quoteInPool": 167.1,    // quote side of pool reserves (quote-token units)
    "vTokensInBondingCurve": 0, // virtual tokens on the curve (pre-migration only)
    "uri": "https://ipfs.io/ipfs/QmTokenMetadata7xK9",
    "breakdown": [           // sub-legs when one tx bundles multiple fills
      { "action": "buy", "trader": "Gk2m…", "tokenAmount": 10000000, "quoteAmount": 2.1 },
      { "action": "buy", "trader": "Gk2m…", "tokenAmount": 5200000,  "quoteAmount": 1.1 }
    ]
  }
}

market.migrate

Migration event on the market lane — marks the curve→AMM transition together with the market cap it happened at.

Example event
{
  "v": 1,
  "id": "9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f",
  "kind": "market.migrate",
  "ts": 1756915750000,
  "wallTs": 1756915750123,
  "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
  "payload": {
    "kind": "market.migrate",
    "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
    "symbol": "BUBU",
    "timestamp": 1756915750000, // migration time (ms)
    "marketCapQuote": 168.4,    // market cap in quote-token units at migration
    "mayhemMode": false
  }
}

market.candle.live / market.candle.closed

OHLCV candles aggregated from the trade feed on 4 timeframes. `live` re-emits the in-progress bucket on every tick; `closed` fires once at bucket end. All prices are market cap in SOL.

Example event
{
  "v": 1,
  "id": "0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
  "kind": "market.candle.closed", // "market.candle.live" | "market.candle.closed"
  "ts": 1756915680000,            // = payload.tsOpen (bucket start), NOT wall time
  "wallTs": 1756915740123,
  "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
  "payload": {
    "kind": "market.candle.closed",
    "mint": "5hBzKpR3vNqXw7TjLmYc8UdAeBsFgHjKlMnOpQrStUvW",
    "symbol": "BUBU",
    "tf": "1m",            // "1m" | "5m" | "15m" | "1h"
    "open": 140.2,         // bucket-open market cap (quote-token units)
    "high": 152.8,         // max market cap (quote-token units) in bucket
    "low": 138.9,          // min market cap (quote-token units) in bucket
    "close": 149.1,        // latest market cap (quote-token units) in bucket
    "vSol": 22.4,          // volume in quote-token units inside the bucket
    "trades": 61,          // trade count
    "buys": 40,            // buy count
    "sells": 21,           // sell count
    "tsOpen": 1756915680000,  // epoch-aligned bucket start (ms)
    "tsClose": 1756915740000  // bucket end (ms) = tsOpen + tf
  }
}

Subscription lifecycle

  • Activation automatic once payment confirms on-chain (poll every 30s).
  • Grace after expiry you keep receiving for 24h while a renewal lands.
  • Renewal a new tier extends from your current expiry; no lost days.
  • Rate limit 10 new connections/s per IP; reuse one connection, subscribe to many channels.

FAQ

Sent the wrong amount?
Payments must match the tier price within 0.001 SOL. Wrong amounts are logged, not credited — generate a new address and send the exact amount.
Connect rejected with 4004?
Subscription expired beyond the 24h grace window. Renew on the dashboard — the same key works again.
Can I filter kinds client-side?
Yes — switch on envelope.kind. New kinds may be added over time, so ignore unknown values instead of throwing.
Devnet SOL for testing?
faucet.solana.com (choose Devnet) or solana airdrop 5 <WALLET> --url devnet.