> ## 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.

# Users

> GET /v1/users: the people who signed in to your platform with CabalSpy ID, newest first, with X profile, KOL badge and verified wallets.

The people who signed in to your platform with CabalSpy ID, newest first. Each entry has the X profile, the KOL badge and the verified wallets. Only users within your plan's user limit are listed.

Users who signed in with Telegram or Google and have no X account have `x` and `twitter` set to null, see [Users without X](/cabalspy-id/openid-connect#users-without-x).

Use it to sync your user base, to build a directory of verified traders, or to find every KOL on your platform with `kol=true`.

<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="limit" default="50" type="integer">
  Users per page, 1 to 100.
</ParamField>

<ParamField query="kol" type="string">
  `true` returns only users with the KOL badge.
</ParamField>

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

<ParamField query="scope" default="instance" type="string">
  `global` lists every CabalSpy ID user. Enterprise plan only.
</ParamField>

<ParamField query="instance" type="string">
  Your Instance ID. Only needed when your account has several instances.
</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/users?limit=50&kol=true" \
    -H "Authorization: Bearer YOUR_KEY"
  ```

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

  H = {"Authorization": "Bearer YOUR_KEY"}
  params = {"limit": 100}
  while True:
      r = requests.get("https://api-id.cabalspy.xyz/v1/users", params=params, headers=H).json()
      for u in r["data"]:
          print(u["username"], u["kol"]["badge"], len(u["wallets"]), "wallets")
      if not r["pagination"]["next_cursor"]:
          break
      params["cursor"] = r["pagination"]["next_cursor"]
  ```

  ```javascript JavaScript theme={null}
  const p = new URLSearchParams({ limit: "50", kol: "true" });
  const res = await fetch(`https://api-id.cabalspy.xyz/v1/users?${p}`, {
    headers: { Authorization: "Bearer YOUR_KEY" },
  });
  const { data, pagination } = await res.json();
  data.forEach(u => console.log(u.username, u.wallets.length));
  ```
</CodeGroup>

## Response

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

<ResponseField name="data" type="array">
  <Expandable title="user">
    <ResponseField name="csid_id" type="string">
      The user's id, the `sub` of their ID token.
    </ResponseField>

    <ResponseField name="username" type="string">
      X handle, or `tg.<telegram username>` / `id.<10 hex characters>` for users without X.
    </ResponseField>

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

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

    <ResponseField name="bio" type="string">
      X bio, null without X.
    </ResponseField>

    <ResponseField name="twitter" type="string">
      X profile link, null without X.
    </ResponseField>

    <ResponseField name="telegram" type="string">
      Link to the verified Telegram account (`https://t.me/<username>`), or an empty string.
    </ResponseField>

    <ResponseField name="x" type="object">
      X account: id, followers, following, verified, verified\_type. Null without X.
    </ResponseField>

    <ResponseField name="kol" type="object">
      badge (boolean) and since (ISO timestamp the badge was granted, or null).
    </ResponseField>

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

    <ResponseField name="wallets" type="array">
      Verified wallets: address, family, chains, verified\_at.
    </ResponseField>

    <ResponseField name="joined_at" type="string">
      When the CabalSpy ID was created.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pagination" type="object">
  <Expandable title="pagination">
    <ResponseField name="limit" type="integer">
      Users per page.
    </ResponseField>

    <ResponseField name="total" type="integer">
      Total users matching the filter.
    </ResponseField>

    <ResponseField name="has_more" type="boolean">
      Whether more pages follow.
    </ResponseField>

    <ResponseField name="next_cursor" type="string">
      Cursor for the next page (null means end).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "data": [
      {
        "csid_id": "0b7c4a52-3f1e-4f43-9d0a-2b5e7c1d9a11",
        "username": "MazeCCC",
        "name": "Maze",
        "image_url": "https://pbs.twimg.com/profile_images/.../photo.jpg",
        "bio": "onchain since 2020",
        "twitter": "https://x.com/MazeCCC",
        "telegram": "",
        "x": {
          "id": "1440000000000000000",
          "followers": 48210,
          "following": 812,
          "verified": true,
          "verified_type": "blue"
        },
        "kol": { "badge": true, "since": "2026-10-10T12:00:00Z" },
        "profile_url": "https://id.cabalspy.xyz/u/MazeCCC",
        "wallets": [
          {
            "address": "7j7AA3HZR2zEjwAQEKPFh2qucLY4fqZpB9iodf39w8xW",
            "family": "solana",
            "chains": ["solana"],
            "verified_at": "2026-10-09T14:21:07Z"
          }
        ],
        "joined_at": "2026-10-09T14:02:51Z"
      }
    ],
    "pagination": {
      "limit": 50,
      "total": 1,
      "has_more": false,
      "next_cursor": null
    },
    "meta": {
      "request_id": "req_5162c7cf7f87",
      "cached": false,
      "cache_age_seconds": 0,
      "version": "v1",
      "timestamp": "2026-10-13T08:04:11Z"
    }
  }
  ```
</ResponseExample>

## Errors

| Status | Code | Meaning |
| - | - | - |
| 400 | invalid\_parameter | limit, cursor or scope invalid. |
| 401 | missing\_api\_key | API key missing. |
| 403 | invalid\_api\_key | API key invalid or not enabled for CabalSpy ID. |
| 403 | scope\_not\_allowed | scope=global needs the Enterprise plan. |
| 429 | rate\_limit\_exceeded | Rate limit exceeded. |

See [Errors](/cabalspy-id/errors) for the full list.


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