> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cabalspy.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# List theses

> GET /v1/theses: the theses of a token, newest or top first, each with the author's real position and PnL.

The theses of one token, newest first or by likes, optionally only bullish or bearish ones. Every thesis carries its author, reaction counts, the app it was posted from and the author's real position in the token.

Theses are public: any API key can read them, for any token, including theses posted on other platforms.

<Tip>
  The list is paginated. Read pagination.next\_cursor from the response and pass it back as cursor to fetch the next page. When next\_cursor is null you have reached the end.
</Tip>

## Query Parameters

<ParamField query="blockchain" type="string" required>
  Chain of the token. One of solana, bnb, base, eth, rh.
</ParamField>

<ParamField query="mint" type="string" required>
  Token address: a Solana mint or a 0x contract address.
</ParamField>

<ParamField query="sort" default="new" type="string">
  `new` (newest first) or `top` (most likes first).
</ParamField>

<ParamField query="stance" type="string">
  Only `bull` or only `bear` theses. Empty means all.
</ParamField>

<ParamField query="limit" default="20" type="integer">
  Theses per page, 1 to 50.
</ParamField>

<ParamField query="cursor" type="string">
  Cursor for the next page, the pagination.next\_cursor from the previous response.
</ParamField>

<ParamField query="csid_id" type="string">
  The viewer, one of your users. Fills my\_reactions and is\_mine.
</ParamField>

<ParamField query="scope" default="global" type="string">
  `global` for theses of all platforms, `instance` for only the theses written on your instance. See [Reach](/cabalspy-id/theses#reach).
</ParamField>

<ParamField query="api_key" type="string" required>
  Your API key. Alternatively pass it as an Authorization Bearer header.
</ParamField>

## Usage Example

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api-id.cabalspy.xyz/v1/theses?blockchain=solana&mint=3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump&sort=top" \
    -H "Authorization: Bearer YOUR_KEY"
  ```

  ```python Python theme={null}
  import requests

  params = {"blockchain": "solana", "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump", "sort": "top"}
  r = requests.get("https://api-id.cabalspy.xyz/v1/theses", params=params,
                   headers={"Authorization": "Bearer YOUR_KEY"})
  for t in r.json()["data"]:
      pos = t["position"].get("now") or {}
      print(t["author"]["username"], t["stance"], t["likes"], pos.get("pnl_usd"), t["body"][:60])
  ```

  ```javascript JavaScript theme={null}
  const p = new URLSearchParams({
    blockchain: "solana",
    mint: "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
    sort: "top",
  });
  const res = await fetch(`https://api-id.cabalspy.xyz/v1/theses?${p}`, {
    headers: { Authorization: "Bearer YOUR_KEY" },
  });
  const { data } = await res.json();
  data.forEach(t => console.log(t.author.username, t.stance, t.position.now?.pnl_usd));
  ```
</CodeGroup>

## Response

<ResponseField name="success" type="boolean">
  True on success.
</ResponseField>

<ResponseField name="data" type="array">
  <Expandable title="thesis">
    <ResponseField name="id" type="string">
      Thesis id.
    </ResponseField>

    <ResponseField name="chain" type="string">
      Chain of the token.
    </ResponseField>

    <ResponseField name="mint" type="string">
      Token address (EVM addresses in lower case).
    </ResponseField>

    <ResponseField name="kind" type="string">
      `thesis` or `reply`.
    </ResponseField>

    <ResponseField name="parent_id" type="string">
      For replies, the thesis replied to. Null for theses.
    </ResponseField>

    <ResponseField name="body" type="string">
      The text, up to 1,000 characters. Plain text, escape it when you render.
    </ResponseField>

    <ResponseField name="stance" type="string">
      `bull`, `bear` or null.
    </ResponseField>

    <ResponseField name="author" type="object">
      <Expandable title="author">
        <ResponseField name="csid_id" type="string">
          The author's CabalSpy ID.
        </ResponseField>

        <ResponseField name="username" type="string">
          X handle.
        </ResponseField>

        <ResponseField name="name" type="string">
          Display name.
        </ResponseField>

        <ResponseField name="image_url" type="string">
          Avatar URL.
        </ResponseField>

        <ResponseField name="kol_badge" type="boolean">
          Whether the author holds the KOL badge.
        </ResponseField>

        <ResponseField name="profile_url" type="string">
          Public CabalSpy ID profile.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="likes" type="integer">
      Number of likes.
    </ResponseField>

    <ResponseField name="replies" type="integer">
      Number of replies.
    </ResponseField>

    <ResponseField name="reactions" type="object">
      Count per reaction, for example `{"like": 4, "🚀": 2}`.
    </ResponseField>

    <ResponseField name="reacted_by" type="array">
      Who reacted, newest first, up to 20 entries.

      <Expandable title="reaction">
        <ResponseField name="emoji" type="string">
          `like` or the emoji.
        </ResponseField>

        <ResponseField name="csid_id" type="string">
          The reacting user's CabalSpy ID.
        </ResponseField>

        <ResponseField name="username" type="string">
          Their X handle.
        </ResponseField>

        <ResponseField name="at" type="string">
          ISO timestamp of the reaction.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="my_reactions" type="array">
      The viewer's own reactions. Empty without csid\_id.
    </ResponseField>

    <ResponseField name="is_mine" type="boolean">
      Whether the viewer wrote it.
    </ResponseField>

    <ResponseField name="via" type="string">
      Name of the app it was posted from, or null when posted on CabalSpy ID itself.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      ISO timestamp.
    </ResponseField>

    <ResponseField name="latest_replies" type="array">
      Theses only. The 3 newest replies, oldest of them first, as full reply objects. Load all replies with [List replies](/cabalspy-id/theses-replies).
    </ResponseField>

    <ResponseField name="position" type="object">
      Theses only, not on replies. The author's position in the token. `{"private": true}` when the author keeps their trading private.

      <Expandable title="position">
        <ResponseField name="at_post" type="object">
          The position when the thesis was posted: invested\_usd, realized\_usd, holding\_value\_usd (null), pnl\_usd (null while holding), pnl\_percent, tokens\_held and first\_buy (ISO timestamp of the first buy).
        </ResponseField>

        <ResponseField name="now" type="object">
          The live position: invested\_usd, realized\_usd, holding\_value\_usd at the current price, pnl\_usd and pnl\_percent (realized plus holding value minus invested), tokens\_held and status (`holding` or `sold`). Values that need a price are null when no price is available.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pagination" type="object">
  limit, total (always null), has\_more and next\_cursor (null means end).
</ResponseField>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "data": [
      {
        "id": "8d1f5a2e-6c4b-4e0f-9a7d-1b2c3d4e5f60",
        "chain": "solana",
        "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
        "kind": "thesis",
        "parent_id": null,
        "body": "Strong community, dev still holding, chart just broke out. Still early.",
        "stance": "bull",
        "author": {
          "csid_id": "0b7c4a52-3f1e-4f43-9d0a-2b5e7c1d9a11",
          "username": "MazeCCC",
          "name": "Maze",
          "image_url": "https://pbs.twimg.com/profile_images/.../photo.jpg",
          "kol_badge": true,
          "profile_url": "https://id.cabalspy.xyz/u/MazeCCC"
        },
        "likes": 4,
        "replies": 1,
        "reactions": { "like": 4, "🚀": 2 },
        "reacted_by": [
          { "emoji": "🚀", "csid_id": "5e2d8c41-7a9b-4c3e-b1f0-6d5e4c3b2a19", "username": "degen_dan", "at": "2026-10-13T09:31:10.204511+00:00" },
          { "emoji": "like", "csid_id": "5e2d8c41-7a9b-4c3e-b1f0-6d5e4c3b2a19", "username": "degen_dan", "at": "2026-10-13T09:30:58.917203+00:00" }
        ],
        "my_reactions": [],
        "via": "Example Terminal",
        "created_at": "2026-10-13T09:12:44.512113+00:00",
        "is_mine": false,
        "latest_replies": [
          {
            "id": "2a9c7e10-4b3d-4f5e-8a6b-7c8d9e0f1a2b",
            "chain": "solana",
            "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
            "kind": "reply",
            "parent_id": "8d1f5a2e-6c4b-4e0f-9a7d-1b2c3d4e5f60",
            "body": "Nice call",
            "stance": null,
            "author": { "csid_id": "5e2d8c41-7a9b-4c3e-b1f0-6d5e4c3b2a19", "username": "degen_dan", "name": "Dan", "image_url": "https://pbs.twimg.com/profile_images/.../photo.jpg", "kol_badge": false, "profile_url": "https://id.cabalspy.xyz/u/degen_dan" },
            "likes": 0,
            "replies": 0,
            "reactions": {},
            "reacted_by": [],
            "my_reactions": [],
            "via": "Example Terminal",
            "created_at": "2026-10-13T09:20:02.118004+00:00",
            "is_mine": false
          }
        ],
        "position": {
          "at_post": {
            "invested_usd": 150.0,
            "realized_usd": 0.0,
            "holding_value_usd": null,
            "pnl_usd": null,
            "pnl_percent": null,
            "tokens_held": 5000.0,
            "first_buy": "2026-10-13T08:12:40+00:00"
          },
          "now": {
            "invested_usd": 150.0,
            "realized_usd": 0.0,
            "holding_value_usd": 231.5,
            "pnl_usd": 81.5,
            "pnl_percent": 54.33,
            "tokens_held": 5000.0,
            "status": "holding"
          }
        }
      }
    ],
    "pagination": {
      "limit": 20,
      "total": null,
      "has_more": false,
      "next_cursor": null
    },
    "meta": {
      "request_id": "req_5162c7cf7f87",
      "cached": false,
      "cache_age_seconds": 0,
      "version": "v1",
      "timestamp": "2026-10-13T10:04:11Z"
    }
  }
  ```
</ResponseExample>

## Errors

| Status | Code | Meaning |
| - | - | - |
| 400 | missing\_parameter | blockchain or mint is missing. |
| 400 | invalid\_parameter | Unknown chain, invalid token address, sort, stance, scope or limit. |
| 401 | missing\_api\_key | API key missing. |
| 403 | invalid\_api\_key | API key invalid or not enabled for CabalSpy ID. |
| 429 | rate\_limit\_exceeded | Rate limit exceeded. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.