Skip to main content

WebSocket

Glowstack exposes a single multiplexed WebSocket that streams every token event we ingest — creations, trades, migrations, holder deltas, and AI signals — with sub-second latency.

wss://stream.glowstack.dev/v1

Connection

Authenticate by passing your key in the Authorization header on the upgrade request. Browsers that cannot set headers may use the ?api_key= query param — server-side only, never ship keys to browsers.

const ws = new WebSocket("wss://stream.glowstack.dev/v1", {
headers: { Authorization: `Bearer ${process.env.ST_KEY}` },
});

ws.on("open", () => ws.send(JSON.stringify({
type: "subscribe",
id: "sub_1",
event: "token.created",
filter: { source: "pumpfun" },
})));
PropertyValue
HeartbeatServer pings every 25s; reply {"type":"pong"} within 15s
Idle timeout60s without a client message
Max subscriptions10 per connection (Pro), 1 (Free)
Compressionpermessage-deflate auto-negotiated; opt-in msgpack

Subscribe

Every subscription has a client-chosen id that is echoed on every event, so you can multiplex many subscriptions on one socket.

{
"type": "subscribe",
"id": "sub_1",
"event": "trade.filled",
"columns": ["mint", "price", "size_usd", "side", "signer"],
"filter": { "mint": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" }
}

The server acknowledges with a subscribed frame. Any validation failure closes the subscription (not the socket) with a typed error frame.

{ "type": "subscribed", "id": "sub_1", "cursor": "c_01HW9K…" }

Unsubscribe

{ "type": "unsubscribe", "id": "sub_1" }

Columns

columns is optional. When omitted, the server sends a sensible default set per event. When present, the server projects to exactly those fields — saving you bandwidth and parse time.

ColumnTypeNotes
mintstringBase58 mint address
symbolstringToken symbol, nullable
pricenumberUSD, 8 decimals
size_usdnumberTrade size in USD
side"buy" | "sell"Classified against pool reserves
signerstringTx signer wallet
signalstringCurrent AI signal, nullable
updated_atstringISO 8601 UTC

Filters

Filters use a columnar expression language. Every filter key is a column name; values are literals, ranges, or $in arrays.

{
"filter": {
"source": "pumpfun",
"mcap": { "$gte": 100000, "$lte": 5000000 },
"signal": { "$in": ["accumulation", "pre_migration"] }
}
}

Compound filters use $and / $or:

{
"filter": {
"$or": [
{ "signal": "insider_spike" },
{ "$and": [{ "holders": { "$gte": 500 } }, { "age_min": { "$lte": 60 } }] }
]
}
}

Events

All event frames share the envelope:

{ "type": "event", "id": "sub_1", "event": "token.created", "data": { /* ... */ } }
EventEmitted when
token.createdA new mint is detected on PumpFun, Meteora, or Raydium launchpad
token.migratedBonding curve completes and liquidity moves to AMM
trade.filledSwap classified against a tracked pool
holder.deltaTop-100 holder set changes (debounced 5s)
signal.emittedAn AI model emits a new or upgraded signal

Each event has a typed data payload — see the event schemas for the full contract.