Advanced Data Stream
The per-pool streams answer "what happened to this token". This one answers "what happened in this transaction", for every transaction on every launchpad we index. It comes as a plain WebSocket, the fastest way in, and as the Socket.IO event stream. Comes with Lite and Developer: connect with your plan's key.
Use it for copy-trading, scam filtering and anything that needs the whole market rather than one pool. If you only care about a few tokens, subscribe_trades is cheaper for you and for us.
| Connect | wss://sol.shrine.trade/api/stream/ws, a plain WebSocket (fastest), or the Socket.IO event stream |
| Auth | your plan's key: ?key= or an x-api-key header on the WebSocket, auth: { api_key } on Socket.IO |
| Plan | Lite (2 sockets) and Developer (5 sockets) |
| Filter | optional protocols and actions lists |
| Resume | sinceSlot: everything since that slot first, then live |
Disconnected? Reconnect with sinceSlot and everything since that slot is sent first; see Replay and resume. For the same transactions before they execute, see Ultra Fast Shred Stream.
Subscribe once with no filter and you have the whole market: every trade, launch, migration and liquidity change on every launchpad we index, one event per transaction. Narrow it with protocols and actions when you only want part of it.
How it compares
Connect
A plain WebSocket, sent by the API process that reads the chain with nothing in between. Each message is one event, the JSON under Payload.
wss://sol.shrine.trade/api/stream/ws?key=sk_…&protocols=PUMPFUN,PUMPSWAP&actions=buy,sell
| Parameter | |
|---|---|
key | your plan's key (or send it as an x-api-key header) |
protocols | optional, comma-separated: only these launchpads |
actions | optional, comma-separated: only these actions |
sinceSlot | optional: resume, everything since that slot first (Replay and resume) |
Leave protocols and actions out for everything. To change them on an open socket, send {"protocols": [...], "actions": [...]}; {"ping": 1} answers {"type": "pong"}. The first message is {"type": "connected", ...} with the filter in force; messages with a type are about the socket, every other one is an event. On a private link the address is ws://<private address>:8080/api/stream/ws.
- JavaScript
- Python
import WebSocket from "ws";
const ws = new WebSocket("wss://sol.shrine.trade/api/stream/ws?key=sk_…&actions=buy,sell,create");
ws.on("message", (raw) => {
const e = JSON.parse(raw);
if (e.type) return; // connected, resumed, pong, subscribed, lagged
console.log(e.action, e.protocol, e.mint, e.quoteAmount);
});
import asyncio, json, websockets
async def main():
url = "wss://sol.shrine.trade/api/stream/ws?key=sk_…&protocols=PUMPFUN"
async with websockets.connect(url) as ws:
async for raw in ws:
e = json.loads(raw)
if "type" in e:
continue # connected, resumed, pong, subscribed, lagged
print(e["action"], e.get("mint"), e.get("quoteAmount"))
asyncio.run(main())
Socket.IO
The same events as the Socket.IO event stream, for clients that already speak Socket.IO or want other streams on the same connection. It passes through one more service on our side, so it arrives about 1 to 2 ms after the plain WebSocket at the median.
- JavaScript
- Python
import { io } from "socket.io-client";
const socket = io("https://sol.shrine.trade", { auth: { api_key: "sk_…" } });
// Everything, or narrow it: protocols and/or actions.
socket.emit("subscribe_stream", {
protocols: ["PUMPFUN", "PUMPSWAP", "STONKFUN"],
actions: ["buy", "sell", "create"],
});
socket.on("stream", (e) => {
if (e.action === "create" && (e.mintAuthority || e.freezeAuthority)) return; // not a clean launch
if (e.action === "buy") console.log(e.mint, e.tradersInvolved, e.quoteAmount, e.price);
});
// later, to stop (free): socket.emit("unsubscribe_stream");
import socketio
sio = socketio.Client()
sio.connect("https://sol.shrine.trade", auth={"api_key": "sk_…"})
sio.emit("subscribe_stream", {"actions": ["create", "migrate"]})
@sio.on("stream")
def on_stream(e):
print(e["action"], e["protocol"], e.get("mint"), e.get("tradersInvolved"))
sio.wait()
Actions
action | When | Protocols |
|---|---|---|
buy / sell | Any swap. One event per pool per transaction; several swaps in one transaction are aggregated with a per-swap breakdown. | every launchpad |
create | A launchpad mint. | PUMPFUN, PUMPFUN_MAYHEM, BONK, STONKFUN, METEORA_DBC |
createPool | An AMM pool opened on an existing token. | PUMPSWAP, RAYDIUM, RAYDIUM_CLMM, METEORA, METEORA_DLMM, ORCA |
migrate | A curve graduating into its AMM. | PUMPFUN→PumpSwap, BONK and STONKFUN→Raydium, METEORA_DBC→DAMM v2 |
curveComplete | A DBC curve filled, before migration. | METEORA_DBC |
curveComplete | A pump.fun curve filled by the trade in this transaction, before migration. | PUMPFUN |
add / remove | Liquidity provided or withdrawn. | PumpSwap, Raydium CPMM and AMM v4, DAMM v2, DLMM, Orca |
claimCreatorFees | A creator collecting fees. | PUMPFUN, PUMPSWAP |
sweep | Fees a trade kept on its curve or pool paid out to the protocol or the creator's vault. Not a trade: no price, no volume. | PUMPFUN, PUMPSWAP |
Payload
Every event carries signature, block, timestamp, action, protocol and txSigner, the fee payer. block is the slot and timestamp is the chain's own time for that slot, the second getBlockTime answers for it, on every launchpad; two trades in one slot carry the same second. txSigner is not always the trader: bots route through relayers. For copy-trading use tradersInvolved. txIndex is the transaction's place in its block: with each breakdown entry's ixIndex and innerIndex it gives the chain's order of every swap. A pool's events are sent in that order, with one exception: a transaction that trades several pools (a route, an arbitrage) goes out in its first pool's turn, so in the other pools it can arrive a moment early or late.
Trades
{
"signature": "…", "block": 445627693, "timestamp": 1788976012, "txIndex": 412,
"action": "buy", "protocol": "PUMPFUN", "txSigner": "…",
"pool": "…", "mint": "…", "quoteMint": "So111…",
"tokenAmount": 31952.74, "quoteAmount": 0.0161, "price": 0.000000504,
"tokenAmountRaw": "31952740000", "quoteAmountRaw": "16100000",
"marketCapQuote": 504.1, "tokensInPool": 1041000000, "quoteInPool": 30.5,
"tokensInPoolRaw": "1041000000000000", "quoteInPoolRaw": "30500000000",
"tradersInvolved": ["…"],
"breakdown": [
{ "trader": "…", "action": "buy", "tokenAmount": 31952.74, "quoteAmount": 0.0161, "price": 0.000000504,
"tokenAmountRaw": "31952740000", "quoteAmountRaw": "16100000",
"tokensInPool": 1041000000, "quoteInPool": 30.5, "tokensInPoolRaw": "1041000000000000", "quoteInPoolRaw": "30500000000",
"ixIndex": 3, "innerIndex": 2 }
]
}
price is what the last swap paid per token: its quote amount over its token amount (the price the candles and token_update carry). tokensInPool and quoteInPool are the pool's reserves as the launchpad reports them: a pump.fun curve's after the trade, a PumpSwap pool's vaults before it. With several swaps in one pool, the event's reserves are the pool's state around the whole transaction (a PumpSwap pool's before the first swap, a curve's after the last trade) and every breakdown entry carries its own. marketCapQuote is price times supply, in the quote asset. Amounts are in UI units, each scaled by its own mint's decimals. Each amount and reserve also comes raw, in the mint's smallest unit, as an integer string under the same name with Raw added (tokenAmountRaw, quoteInPoolRaw, …): exact at any size, where a float loses the last units on a large pool.
One event per pool per transaction. With swaps both ways, tokenAmount and quoteAmount are the nets and action is the side of the net token amount (of the net quote amount when the tokens net to zero, of the first swap when both do); the swaps themselves are in breakdown.
PumpSwap trades also carry what pricing the pool takes. virtualQuoteReserves is the pool's virtual quote reserve the swap was priced at, signed: the pool prices against quoteInPool plus it. It is on the event (before its first swap) and on every breakdown entry. Each entry also carries userQuoteAmount and fees, rates in basis points and amounts in the quote asset, each amount raw too (lpRaw, protocolRaw, …).
quoteAmount and userQuoteAmount are the program's own two amounts. On a sell, and on a buy of a set number of tokens, quoteAmount is before fees and userQuoteAmount is what the trader got or paid with them. On a buy that spends a set amount (buy_exact_quote_in, most PumpSwap buys) the program reports them the other way round: quoteAmount is what the trader paid, fees included, and userQuoteAmount is what the swap was priced on once the fees came off. A buy whose userQuoteAmount is below its quoteAmount is one of these.
{ "trader": "…", "action": "sell", "tokenAmount": 120000, "quoteAmount": 0.84, "price": 0.000007,
"tokensInPool": 140000000, "quoteInPool": 92.1, "virtualQuoteReserves": 17.6, "userQuoteAmount": 0.8375,
"fees": { "lpBps": 20, "lp": 0.00168, "protocolBps": 5, "protocol": 0.00042, "creatorBps": 5, "creator": 0.00042,
"cashbackBps": 0, "cashback": 0, "lpRaw": "1680000", "protocolRaw": "420000", "creatorRaw": "420000", "cashbackRaw": "0" },
"ixIndex": 2, "innerIndex": 4 }
Some pools hold SOL as their base and the coin as their quote, a few busy ones among them (about a third of PumpSwap swaps). There the pool's quote is the coin, so the same fields are in the coin and named from its side: virtualTokenReserves (the pool prices against tokensInPool plus it), userTokenAmount and tokenFees. quoteAmount and tokenAmount stay SOL and the coin as everywhere else. Between SOL and USDC, USDC is the coin, priced in SOL, whichever side the pool holds them on.
Two pump.fun cases carry extra fields:
- A buy that completes the curve. The event carries
"completesCurve": trueand thebreakdownentry that emptied the curve is tagged"stage": "curve". A v3 buy may take more than the curve has left: it empties the curve at the curve's price, then buys the rest from the tokens the migration deposits, at the price that pool opens with. That second part is a furtherbreakdownentry for the same trader tagged"stage": "postComplete"; the event'stokenAmountandquoteAmountare then the buyer's total,priceis the second part's, and the reserves are the pool's opening state. AcurveCompleteevent follows in the same transaction. - A multi-hop route. A PumpSwap
multi_hop_swaptrades through several pools and curves in one instruction, for coins paired with another pump coin. Each hop is a normalbuyorsellon its own pool, tagged"via": "multi_hop"on the event and on itsbreakdownentries. The middle coins net to zero for the trader; the volume on every pool is real.
Fee sweeps
{
"action": "sweep", "protocol": "PUMPFUN",
"mint": "…", "pool": "…", "quoteMint": "So111…",
"recipient": "…", "fee": "creator", "bucket": 1,
"amount": 0.000888889, "amountRaw": 888889
}
v3 curve trades and v2 pool trades keep the protocol fee and the creator fee where the trade happened; a sweep pays them out later. fee is protocol (bucket 0) or creator (bucket 1), amount is in the quote asset. Fee income is in the trades; a sweep is the payout, not new income.
Creates
{
"action": "create", "protocol": "PUMPFUN",
"mint": "…", "pool": "…", "quoteMint": "So111…", "creator": "…",
"name": "…", "symbol": "…", "uri": "…", "decimals": 6, "supply": 1000000000, "supplyRaw": "1000000000000000",
"tokensInPool": 1073000000, "quoteInPool": 30, "tokensInPoolRaw": "1073000000000000", "quoteInPoolRaw": "30000000000",
"initialBuy": { "quoteAmount": 0.5, "tokenAmount": 17000000, "quoteAmountRaw": "500000000", "tokenAmountRaw": "17000000000000" },
"mintAuthority": null, "freezeAuthority": null, "tokenExtensions": []
}
creator is the creator the launchpad records for the coin, the wallet its creator fees go to. A launch service may sign the create for someone else, so it is not always txSigner. mintAuthority and freezeAuthority should both be null on an honest launch; a value means supply can be minted or wallets frozen. tokenExtensions lists Token-2022 extensions by name; transferFeeConfig and permanentDelegate deserve a look outside trusted launchpads. initialBuy is the launcher's own buy in the launch transaction (on pump.fun, the buys by the wallet that sent the create and by the creator), null if there was none; other wallets buying in the same transaction come as trades. Authorities and extensions are read from the mint account as it was created; if the mint predates the stream they may be absent.
Migrations and pools
Migrations carry fromPool, toPool and toProtocol. Pool creates carry pool, creator and, when known, mint and quoteMint, named as the pool's trades name them: on a SOL-base pool mint is the coin. A PumpSwap pool create also carries its opening reserves, tokensInPool and quoteInPool. Liquidity events carry pool, owner and the raw amounts of both sides (amountARaw, amountBRaw); the side-to-mint mapping follows the launchpad's own ordering.
Try it
Notes
- One connection per client, please. Everything is filtered per socket, so open one socket and subscribe once.
- Events for a transaction are emitted in a fixed order: trades, then creates and pool creates, then migrations, liquidity and sweeps, then fee claims.
- A pool's events go out in the chain's order, except a transaction that trades several pools: it goes out in its first pool's turn and can arrive a moment early or late in the others. Where order matters, and across pools, sort by
block,txIndex, then each swap'sixIndexandinnerIndex. - Events go out as soon as a block is seen, before the network confirms it. Now and then a block is dropped and its transactions land again in a later one: the same
signaturethen comes twice, with a differentblockandtxIndex. Only one of the two blocks stays in the chain, nearly always the later. More rarely, a block's transactions are first run on a state the network then drops: those events keep theirblockandtxIndex, but amounts and reserves can differ from the final chain's, and a transaction that fails in the final block can come as a trade (3 events in two hours on 2026-10-29). Where an event must be exact, check its transaction once its block is confirmed. - Every event on this stream is also archived by the hour for backtesting: see Historical replay.
LimitsLite 2 socketsDeveloper 5 socketsSee plans →