Build a pump.fun copy trading bot with WebSocket streams
How to build a pump.fun copy trading bot: leader swaps over WebSocket, a live rug-check gate on every signal, mirrored exits — the data side, end to end.
How to build a pump.fun copy trading bot: leader swaps over WebSocket, a live rug-check gate on every signal, mirrored exits — the data side, end to end.
A copy trading bot has two halves. The execution half — keys, signing, submission, landing — is yours and is not covered here. The data half — knowing that a wallet worth copying just bought, in sub-second, with enough context to decide whether to follow — is what this guide builds, end to end, on the Raiden API. Raiden supplies the eyes of a pump.fun copy trading bot; you bring the hands. Getting the eyes right is where most solana copy trading bot projects quietly fail: they detect too slowly, mirror blindly, and never handle the exit.
| # | Layer | What it does | API surface |
|---|---|---|---|
| 1 | Leader list | The wallets worth mirroring, saved server-side | POST /wallet-groups + …/wallets |
| 2 | Stream | A subscription that pushes only those wallets' fills | POST /ws-subscriptions |
| 3 | Listener | The WebSocket connection consuming type: swap events | wss://terminal.raiden.wtf/ws |
| 4 | Risk gate | Pre-trade checks on every signal before mirroring | /tokens/{mint}/trust, /tokens/{mint}/swaps |
| 5 | Exit mirror | The leader's sell is a swap event too — act on it | same stream |
A copy bot is only as good as the wallets it copies. How to find and vet them — realized PnL net of all fees, win rate, hold style, and the traps in each metric — is its own guide: the best Solana wallets to copy trade. Vetting runs on a 6-month rolling window of history (complete record since May 1, 2026), so a leader's track record is checkable before you wire money to its signals. Once you have the shortlist, save it as a wallet group — streams filter by group id, never by inline addresses:
curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"name":"Copy leaders"}' "https://terminal.raiden.wtf/api/wallet-groups" { "id": "grp_5f3a…", "name": "Copy leaders", "count": 0, "members": [] } curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"wallets":["8psN…VRtf","Cb3f…g9rE"]}' \ "https://terminal.raiden.wtf/api/wallet-groups/grp_5f3a…/wallets" { "ok": true, "added": 2 }
Adds are idempotent and a group holds up to 1,000 wallets. The stream resolves the
group into a wallet snapshot when it is created or updated — so after editing the
roster later (drop a decaying leader, add a new one), re-issue a PUT on
the stream to re-resolve the list. The sub token stays the same, so the bot itself
never changes.
One call creates a push subscription for the swaps kind, filtered to your
group. The response contains the opaque token you connect with:
curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"name":"copy-leaders","kinds":["swaps"],"wallet_list_id":"grp_5f3a…"}' \ "https://terminal.raiden.wtf/api/ws-subscriptions" { "id": 3, "token": "sub_a1b2c3…", "name": "copy-leaders", "active": true, "kinds": ["swaps"], "wallet_list_id": "grp_5f3a…", "wallets": ["8psN…VRtf", "Cb3f…g9rE"] }
Accounts get 3 streams by default — enough to split leaders by strategy (one stream of scalpers, one of holders) and size the mirror differently per stream. The full stream system — all five kinds, filters, reconnection — is covered in the pump.fun WebSocket guide.
Connect with your API key and the sub token; only events matching the stream's kinds
and filters are pushed. Every fill by a tracked wallet arrives as a
type: swap event:
wscat -c "wss://terminal.raiden.wtf/ws?key=$RAIDEN_KEY&sub=sub_a1b2c3…" { "topic": "sub:3", "type": "swap", "time": "2026-07-13T09:01:22.400Z", "mint": "…pump", "trader": "8psN…VRtf", "is_buy": true, "sol_amount": 4200000000, "token_amount": 191833, "price": "0.0000041", "sig": "…", "slot": 351902144, "tip": 100000 }
token_amount is in raw token base units. REST endpoints
return large numbers as strings; the WebSocket swap event pushes them as numbers, with
price as a string. A sol_amount of 4200000000
is a 4.2 SOL buy.
This event is the entire signal: who (trader), what (mint),
which direction (is_buy), how big (sol_amount), at what
price, in which slot. To copy trade pump.fun wallets you now need the part most
bots get wrong — deciding whether to mirror.
A raw mirror ("leader bought → I buy") is a machine for inheriting other people's exit liquidity. Three checks — each a single API call — separate a bot from a donation:
GET /tokens/{mint}/trust returns a live 0–100
score with a verdict: clean (≥65), caution (40–64),
likely_rug (<40). Never mirror a buy into likely_rug —
the leader may be an insider entering a position you cannot exit, or exit-scalping a
dump you will hold. The score blends dev reputation, known rug-dumpers currently in
the token, bundled supply, dev exit and wash trading; the full methodology is in
the pump.fun rug check guide.sol_amount with a hard cap keeps
your exposure proportional to theirs.GET /tokens/{mint}/swaps?order=desc&limit=1 returns the
latest indexed trade — compare its price to the event's. If the token
already ran well past the leader's entry, you are not copying a trade, you are
chasing one.curl -H "X-API-Key: $RAIDEN_KEY" "https://terminal.raiden.wtf/api/tokens/…pump/trust" { "mint": "…pump", "score": 45, "verdict": "caution", "capped": true, "cap_reason": "bundled", "signals": { "dev_score": { "value": 0, "comp": 8.4, "known": true }, "dumpers_holding": { "value": 3, "comp": 15.0, "known": true }, "bundled_pct": { "value": 52.0, "comp": 0.0, "known": true }, … } }
The leader's sell is also a swap event — same stream, is_buy: false. A
copy bot that mirrors entries but not exits is long everything its leaders have
already left; mirroring the exit is three lines in the listener below. One caveat
decides whether a leader is copyable at all: the fast flip. A sniper that lands
in the same slot as the token creation has entered — and often exited — inside a
window no external signal can beat; with human or API latency you would buy its exit.
Before wiring a leader in, measure it: GET /versus scores 2–5 wallets on
their shared tokens with per-fill slot and block-index timing, and
the wallet-landing guide shows how
to read the result. Leaders whose edge is selection, not landing — entries several
slots after creation, holds measured in minutes — are the ones mirror trading
solana style actually works on.
import asyncio, json, requests, websockets BASE = "https://terminal.raiden.wtf/api" KEY = "YOUR_KEY" H = {"X-API-Key": KEY} WS = f"wss://terminal.raiden.wtf/ws?key={KEY}&sub=sub_a1b2c3…" MIRROR_RATIO = 0.10 # copy 10% of the leader's size MAX_LAMPORTS = 500_000_000 # hard cap per entry (0.5 SOL) MAX_CHASE = 0.15 # skip if price already ran >15% past the fill positions = {} # mint -> lamports we hold def risk_gate(ev): """Return a sized buy in lamports, or None to skip.""" mint = ev["mint"] # 1 · trust verdict — never mirror into a likely rug t = requests.get(f"{BASE}/tokens/{mint}/trust", headers=H).json() if t["verdict"] == "likely_rug": return None # 2 · slippage guard — latest indexed price vs the leader's fill last = requests.get(f"{BASE}/tokens/{mint}/swaps", params={"order": "desc", "limit": 1}, headers=H).json()["data"] if last and float(last[0]["price"]) > float(ev["price"]) * (1 + MAX_CHASE): return None # already ran away — chasing, not copying # 3 · size relative to the leader, capped return min(int(ev["sol_amount"] * MIRROR_RATIO), MAX_LAMPORTS) def execute_buy(mint, lamports): # === YOUR STACK: build, sign, submit, confirm === raise NotImplementedError def execute_sell(mint): # === YOUR STACK === raise NotImplementedError async def listen(): async with websockets.connect(WS) as ws: async for raw in ws: ev = json.loads(raw) if ev.get("type") != "swap": continue mint = ev["mint"] if ev["is_buy"]: if mint in positions: continue # already in — don't stack entries size = risk_gate(ev) if size: execute_buy(mint, size) positions[mint] = size elif mint in positions: # the leader's SELL — mirror the exit execute_sell(mint) del positions[mint] asyncio.run(listen())
requests
calls for clarity — move them to an async client so one slow lookup never delays the
next event. Reconnect with backoff, and treat a restart as a state problem: your
positions dict must survive it, or exits will be missed.Everything above is public API surface — full request and response shapes are in the API reference, and a free key with 200,000 trial credits (see the pump.fun API overview) is enough to build and test the whole data half before a single SOL is at risk.
No. Raiden is the data side only: it detects the leader's fill and pushes it to you in sub-second over WebSocket, and gives you the risk data to decide. Signing, submission and execution are your own stack — there is no trading API.
Gate every buy signal through the live trust score: GET /tokens/{mint}/trust returns a 0-100 score and a verdict — clean, caution or likely_rug. Never mirror a buy into a likely_rug token, whatever the leader does; insider entries are often positions you cannot exit.
Not profitably. A sniper that lands in the same slot as the token creation has entered — and often exited — before any external signal can reach your bot. Measure a candidate leader's timing with /versus first: if its edge is same-slot landing, pick a slower leader.
Yes — every swap event carries is_buy. A leader's sell arrives on the same stream as its buys, so the listener that mirrors entries can mirror exits with three extra lines. Most losing copy bots copy only the entry.
The swaps kind is filtered by a wallet group, and a group holds up to 1,000 wallets. Accounts get 3 streams by default, so a single account can follow thousands of leaders split across streams.
The trader, the mint, is_buy, sol_amount in lamports, token_amount in raw token units, the price, the slot, the transaction signature and the tip — enough to size and gate a mirror decision, with the mint ready for a trust lookup before you act.
Build on the same data
Free API key with 200,000 trial credits: full REST and WebSocket access to the same firehose that powers the Terminal. Connect a Solana wallet; no email, no card.