For the complete documentation index, see llms.txt. This page is also available as Markdown.
Bundle
KOL bundle / side-wallet detection on Solana, grouped per token.
Bundle Stream — KOL Bundle / Side-Wallet Detection (WebSocket)
get
Real-time WebSocket stream of KOL bundles. CabalSpy detects wallets that a KOL controls or coordinates with — "side wallets" that buy the same token in the same Jito bundle or the same block as the KOL — and delivers them grouped per token, each with a full live position (bought, sold, held, unrealized PnL, remaining value).
Solana only. A bundle only exists because a KOL bought the token, so the token is always tracked and its market cap is always available — which is why positions and unrealized PnL can be computed for the bundle wallets too.
Whole-token delivery
You always receive the whole token, not a single bundle. Every message carries the complete current picture for one token: the bundles list holds all bundles detected in that token (a token can have several, each with a different KOL), and each bundle holds all of its wallets. When anything changes, the entire token is re-sent, so you simply replace your view of that token with the latest message — no need to merge partial updates.
Each bundle carries its own KOL
A token can contain bundles from several different KOLs. Every entry in bundles therefore has its ownkol_wallet and kol_profile, and the KOL is also included inside that bundle's bundle_wallets list with is_kol: true and the same position fields as the side wallets. Take the KOL identity from each bundle's own kol_wallet / kol_profile — there is no token-level KOL, because a token can have many.
Confidence, not two event types
Confirmed side wallets and structural leads are merged into one shape, distinguished by confidence: low | medium | high | verified. verified means Jito-confirmed (jito_confirmed: true, with a bundle_id); lower tiers are on-chain footprint leads (adjacent in block, matching fee, recurrence) that are not Jito-confirmed. Each bundle also carries a human-readable proof and a verify_hint. A wallet's transaction_type is buy or sell; there is no separate sell event.
Two subscription modes — this controls how much you receive (and pay)
Every delivered message counts as one credit. The mode you subscribe with decides how many messages you get:
mode: "full" (default) — you receive the token again on every relevant change, INCLUDING marketcap ticks, so unrealized_pnl_* and remaining_* stay live to the second. Ideal for a live holder/positions table, but chatty: an active token can produce thousands of updates (and thus thousands of credits) per hour.
mode: "events" — you receive the token only on real events: a new bundle is detected, or a bundle wallet buys or sells. Marketcap-driven updates are NOT sent. Positions are still included, computed at the moment of the event. This is the economical choice when you only need to know that a bundle exists and when wallets trade. Example: 3 bundles and 10 sells on a token cost 13 credits instead of thousands.
Combine mode with the token selector freely: one token + full (live table), one token + events (cheap event feed), * + full (everything live — very high volume), * + events (every new bundle network-wide, events only).
Message events
init — one-time snapshot of all known bundles for the token at subscribe time, rebuilt from CabalSpy's store (survives restarts; positions recomputed with the current market cap). Sent in both modes.
kol_bundle — an update. In full mode this fires on new detections, trades, AND marketcap moves. In events mode it fires ONLY on new detections and trades.
Connect
Open a WebSocket to wss://stream.cabalspy.xyz with your API key as a query parameter (?apiKey=YOUR_KEY) or a Bearer header (Authorization: Bearer YOUR_KEY). You receive a {"type":"connected"} welcome.
Subscribe
{ "op":"subscribe", "stream":"bundle", "blockchain":"solana", "token":"<mint>", "mode":"events" }. Bundles are always token-scoped. Use "*" to receive bundles across all tokens. A concrete mint returns an init snapshot first. Omit mode (or set "full") for live marketcap-driven updates. The server replies with a subscribed ack echoing the filters (including the resolved mode).
Unsubscribe
{ "op":"unsubscribe", "stream":"bundle", "token":"<mint>" } — stops all updates for that token.
List / Ping
{ "op":"subscriptions" } lists active subscriptions; { "op":"ping" } returns a pong.
'events' = only real events (new bundle, buy, sell); no marketcap updates; cheapest. 'full' = adds live marketcap-driven position updates (uPNL/remaining stay live); higher credit usage.
Default: fullPossible values:
channelstring · nullableOptional
Alternative to blockchain+token: bundle.solana. or bundle.solana for all. (Pass mode as a separate field.)
Responses
200
init and kol_bundle messages. (The connection also delivers a connected welcome, a subscribed ack per subscribe, and error messages — see schemas.)
application/json
One bundle message — init snapshot or live kol_bundle update. ALWAYS the whole token: bundles contains every bundle detected in the token, each with its own KOL and wallets. Replace your view of the token with each message.
successbooleanOptionalExample: true
channelstringOptionalExample: bundle.solana
eventstring · enumOptionalPossible values:
get/bundle
200
init and kol_bundle messages. (The connection also delivers a connected welcome, a subscribed ack per subscribe, and error messages — see schemas.)