> For the complete documentation index, see [llms.txt](https://cabalspy.gitbook.io/cabalspy-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cabalspy.gitbook.io/cabalspy-docs/bundle/bundles.md).

# Bundles

Snapshot of KOL + side-wallet bundles detected for a Solana token, with live per-wallet positions (held, bag %, supply %, realized & unrealized PnL).

## Bundle Snapshot — all bundles for one token

> Returns a point-in-time snapshot of every bundle detected for the given \`mint\`, with each member wallet's live position. All bundles for the token are included on every call.\
> \
> \*\*Required:\*\* \`blockchain\` (must be \`solana\`) and \`mint\`.\
> \
> If no bundle has been detected for the token yet (or its snapshot has aged out of Redis), the response is still \`200\` with a populated \`token\` block and an empty \`bundles\` array — poll again once activity appears.<br>

```json
{"openapi":"3.0.3","info":{"title":"CabalSpy API — KOL Bundles (Snapshot)","version":"1.0.0"},"tags":[{"name":"Bundles","description":"Snapshot of KOL + side-wallet bundles detected for a Solana token, with live per-wallet positions (held, bag %, supply %, realized & unrealized PnL).\n"}],"servers":[{"url":"https://api.cabalspy.xyz"}],"security":[{"bearerAuth":[]},{"apiKeyQuery":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}},"schemas":{"BundleEnvelope":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"blockchain":{"type":"string","enum":["solana"]},"token":{"$ref":"#/components/schemas/BundleTokenBlock"},"bundles":{"type":"array","description":"All bundles detected for the token. Empty when none detected yet.","items":{"$ref":"#/components/schemas/Bundle"}}}},"meta":{"type":"object","properties":{"request_id":{"type":"string"},"cached":{"type":"boolean"},"cache_age_seconds":{"type":"integer"},"version":{"type":"string"},"timestamp":{"type":"string","description":"ISO timestamp of the response."}}}}},"BundleTokenBlock":{"type":"object","description":"Token identity + current market-cap / bonding-curve state. Market fields are null when no live market cap is cached for the token.","properties":{"mint":{"type":"string"},"symbol":{"type":"string","description":"Token symbol. May be empty (\"\") — bundles carry no on-chain metadata lookup."},"name":{"type":"string","description":"Token name. May be empty (\"\")."},"supply":{"type":"number","nullable":true,"description":"Total supply. Derived from market_cap / price; falls back to 1e9 (pump default) when unknown."},"market_cap":{"type":"number","nullable":true,"description":"Market cap in SOL (price x supply)."},"market_cap_usd":{"type":"number","nullable":true},"market_cap_currency":{"type":"string","enum":["SOL"],"nullable":true},"price":{"type":"number","nullable":true,"description":"Price in SOL per token."},"price_usd":{"type":"number","nullable":true},"sol_price_usd":{"type":"number","nullable":true,"description":"Current SOL/USD used for all USD conversions in this response."},"pool":{"type":"string","nullable":true,"description":"pump, pump-amm, raydium-launchpad, raydium, …"},"on_curve":{"type":"boolean","nullable":true,"description":"true while still on the bonding curve."},"bonding_curve_progress":{"type":"number","nullable":true,"description":"0–100; 100 after migration."}}},"Bundle":{"type":"object","description":"One detected bundle within a token, led by a single KOL.","properties":{"bundle_id":{"type":"string","nullable":true,"description":"Jito bundle id when confirmed; null for footprint-only detections."},"kol_wallet":{"type":"string","nullable":true,"description":"The KOL that leads this bundle."},"kol_profile":{"allOf":[{"$ref":"#/components/schemas/BundleProfile"}],"nullable":true},"confidence":{"type":"string","enum":["low","medium","high","verified"],"description":"Detection confidence. Only ever improves over the bundle's life."},"jito_confirmed":{"type":"boolean","description":"true when confirmed as an actual Jito bundle."},"proof_type":{"type":"string","nullable":true,"description":"jito_bundle | same_transaction | on_chain_footprint …"},"slot":{"type":"integer","nullable":true},"wallet_count":{"type":"integer","description":"Number of wallets in bundle_wallets (KOL included)."},"proof":{"type":"string","nullable":true,"description":"Human-readable explanation of why this was flagged as a bundle."},"verify_hint":{"type":"string","nullable":true,"description":"Optional pointer for manual verification."},"detected_at":{"type":"string","nullable":true,"description":"ISO timestamp of first detection."},"bundle_wallets":{"type":"array","description":"KOL first, then side wallets sorted by invested (descending).","items":{"$ref":"#/components/schemas/BundleWallet"}}}},"BundleProfile":{"type":"object","description":"Wallet profile. Side wallets are usually not tracked, so their fields are empty and type is null; the KOL carries a full profile with type \"kol\".\n","properties":{"name":{"type":"string"},"image_url":{"type":"string"},"twitter":{"type":"string"},"telegram":{"type":"string"},"blockchain":{"type":"string","enum":["solana"]},"currency":{"type":"string","enum":["SOL"]},"type":{"type":"string","enum":["kol"],"nullable":true,"description":"\"kol\" for the KOL, null for untracked side wallets."}}},"BundleWallet":{"type":"object","description":"One member of a bundle. The KOL (is_kol: true) omits the side-wallet evidence fields (fee_lamports, block_index, adjacent_to_kol, same_fee, occurrences); side wallets include them.\n","properties":{"address":{"type":"string"},"is_kol":{"type":"boolean","description":"true for the bundle's KOL wallet."},"transaction_type":{"type":"string","enum":["buy","sell"],"description":"Last observed action for this wallet in the bundle."},"signature":{"type":"string","nullable":true,"description":"Last transaction signature. Often null for the KOL (its position is mirrored, not event-sourced)."},"entry_source":{"type":"string","nullable":true,"description":"Where the entry market cap came from: at_bundle | at_discovery | null."},"position_source":{"type":"string","enum":["live"],"description":"Always \"live\" (computed from current state)."},"fee_lamports":{"type":"integer","nullable":true,"description":"Side wallets only. Fee paid (lamports)."},"block_index":{"type":"integer","nullable":true,"description":"Side wallets only. Index within the block run."},"adjacent_to_kol":{"type":"boolean","nullable":true,"description":"Side wallets only. Directly adjacent to the KOL tx in the block."},"same_fee":{"type":"boolean","nullable":true,"description":"Side wallets only. Same fee as the KOL."},"occurrences":{"type":"integer","nullable":true,"description":"Side wallets only. How often this wallet has been seen bundling with this KOL."},"profile":{"$ref":"#/components/schemas/BundleProfile"},"position":{"$ref":"#/components/schemas/BundlePosition"}}},"BundlePosition":{"type":"object","description":"Live position of one wallet in the bundle, derived at request time from the raw aggregates plus the token's current market cap. remaining_* and unrealized_* are null when no market cap is available.\n","properties":{"held":{"type":"number","description":"Tokens still held (bought − sold)."},"peak":{"type":"number","description":"All-time peak of held tokens."},"bought_tokens":{"type":"number"},"sold_tokens":{"type":"number"},"bag_pct":{"type":"number","nullable":true,"description":"% of peak holding still held (held / peak x 100)."},"supply_pct":{"type":"number","nullable":true,"description":"% of total supply still held."},"invested":{"type":"number","description":"Cumulative buy value (SOL)."},"invested_usd":{"type":"number","nullable":true},"max_single_buy":{"type":"number","description":"Largest single buy (SOL)."},"buy_txn":{"type":"integer"},"sell_txn":{"type":"integer"},"sold_value":{"type":"number","description":"Cumulative sell value (SOL)."},"sold_value_usd":{"type":"number","nullable":true},"realized_pnl_sol":{"type":"number","description":"sold_value − invested (SOL)."},"realized_pnl_usd":{"type":"number","nullable":true},"entry_market_cap":{"type":"number","nullable":true,"description":"Market cap (SOL) at the wallet's first tracked buy."},"entry_market_cap_usd":{"type":"number","nullable":true},"unrealized_pnl_sol":{"type":"number","nullable":true,"description":"Current bag value − open net cost basis (held_value − (invested − sold_value)). null if market cap unknown. Equals realized when fully out."},"unrealized_pnl_usd":{"type":"number","nullable":true},"unrealized_pnl_pct":{"type":"number","nullable":true,"description":"(current price / avg buy price − 1) x 100."},"remaining_sol":{"type":"number","nullable":true,"description":"Current value of the remaining bag (SOL)."},"remaining_usd":{"type":"number","nullable":true},"first_buy_at":{"type":"string","nullable":true,"description":"ISO timestamp of the first buy."},"last_activity_at":{"type":"string","nullable":true,"description":"ISO timestamp of the last activity."}}},"ErrorEnvelope":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"parameter":{"type":"string","nullable":true},"allowed":{"type":"array","items":{"type":"string"},"nullable":true},"docs":{"type":"string","nullable":true}}}}}}},"paths":{"/v1/bundle":{"get":{"tags":["Bundles"],"summary":"Bundle Snapshot — all bundles for one token","operationId":"getBundle","description":"Returns a point-in-time snapshot of every bundle detected for the given `mint`, with each member wallet's live position. All bundles for the token are included on every call.\n\n**Required:** `blockchain` (must be `solana`) and `mint`.\n\nIf no bundle has been detected for the token yet (or its snapshot has aged out of Redis), the response is still `200` with a populated `token` block and an empty `bundles` array — poll again once activity appears.\n","parameters":[{"name":"blockchain","in":"query","required":true,"description":"Must be solana (bundles are Solana-only).","schema":{"type":"string","enum":["solana"],"default":"solana"}},{"name":"mint","in":"query","required":true,"description":"Token mint address.","schema":{"type":"string"}},{"name":"api_key","in":"query","required":false,"description":"API key (alternative to the Authorization header).","schema":{"type":"string"}}],"responses":{"200":{"description":"Bundle snapshot for the token. `data.bundles[]` is empty when nothing has been detected yet.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BundleEnvelope"}}}},"400":{"description":"Bad request (missing `mint`, or `blockchain` other than solana).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized (missing or invalid API key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden (invalid key or insufficient credits).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}}}
```
