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

# Lists & Communities

# Lists & Communities

The Sorsa API extracts members, tweets, and followers from X Lists. It also covers the legacy X Communities endpoints, though X discontinued Communities in May 2026 (details below). This page is the endpoint reference for both.

> **Note:** For strategic context, cost math, and end-to-end monitoring workflows, see the [X List API guide](https://api.sorsa.io/blog/x-lists-and-communities-api) on the blog.

> **Heads up:** X permanently discontinued Communities on **May 30, 2026**. The three Community endpoints below no longer return live data and are kept here as reference for anyone maintaining legacy code. Use Lists for any new or ongoing workflow.

***

## Lists

An X List is a public collection of up to 5,000 accounts. Lists have two audiences:

* **Members:** accounts added to the list by the curator.
* **Followers (subscribers):** users who subscribed to read the List timeline.

Private Lists are not API-accessible.

| Endpoint             | Method | Returns                                       | Page size |
| :------------------- | :----- | :-------------------------------------------- | :-------- |
| `/v3/list-members`   | GET    | User profiles of accounts in the list         | up to 200 |
| `/v3/list-followers` | GET    | User profiles of accounts following the list  | up to 200 |
| `/v3/list-tweets`    | GET    | Combined chronological feed from list members | \~20      |

The List ID is the numeric value in the list URL: `https://x.com/i/lists/1234567890` means the ID is `1234567890`.

> **Tip:** Every account starts with 100 free requests (no card, no expiry), enough to pull a mid-sized List end to end. Test any endpoint without writing code in the [API Playground](https://api.sorsa.io/playground).

### Get List Members

`GET /v3/list-members`

| Parameter     | Type    | Required | Description                                 |
| :------------ | :------ | :------- | :------------------------------------------ |
| `list_id`     | string  | Yes      | Numeric List ID.                            |
| `next_cursor` | integer | No       | Pagination cursor from a previous response. |

```bash theme={null}
curl "https://api.sorsa.io/v3/list-members?list_id=1234567890" \
  -H "ApiKey: YOUR_API_KEY"
```

```python theme={null}
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY}


def get_list_members(list_id, max_pages=50):
    members, cursor = [], None

    for _ in range(max_pages):
        params = {"list_id": list_id}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-members", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        members.extend(data.get("users", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return members


members = get_list_members("1234567890")
for u in members[:5]:
    print(f"@{u['username']} ({u['followers_count']:,} followers)")
```

A full 5,000-member List takes \~25 requests to extract.

### Get List Followers

`GET /v3/list-followers`

| Parameter     | Type   | Required | Description             |
| :------------ | :----- | :------- | :---------------------- |
| `list_link`   | string | Yes      | List URL or numeric ID. |
| `next_cursor` | string | No       | Pagination cursor.      |

Note the parameter name: `/list-followers` takes `list_link` (URL or ID), while `/list-members` and `/list-tweets` take `list_id` (numeric ID only).

```python theme={null}
def get_list_followers(list_link, max_pages=50):
    followers, cursor = [], None

    for _ in range(max_pages):
        params = {"list_link": list_link}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-followers", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        followers.extend(data.get("users", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return followers


subs = get_list_followers("https://x.com/i/lists/1234567890")
print(f"{len(subs)} subscribers")
```

### Get List Tweets

`GET /v3/list-tweets`

Returns recent tweets from all list members in a single chronological feed. This is the endpoint used in the [Real-Time Monitoring](https://docs.sorsa.io/real-time-monitoring) workflow for tracking groups of accounts with a single request instead of polling each account separately.

| Parameter     | Type   | Required | Description        |
| :------------ | :----- | :------- | :----------------- |
| `list_id`     | string | Yes      | Numeric List ID.   |
| `next_cursor` | string | No       | Pagination cursor. |

```python theme={null}
def get_list_tweets(list_id, max_pages=10):
    tweets, cursor = [], None

    for _ in range(max_pages):
        params = {"list_id": list_id}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-tweets", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        tweets.extend(data.get("tweets", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return tweets


feed = get_list_tweets("1234567890", max_pages=10)
for t in feed[:5]:
    print(f"@{t['user']['username']}: {t['full_text'][:80]}")
```

***

## Communities (discontinued)

> **Communities were discontinued on May 30, 2026.** X announced the shutdown in April 2026 (head of product Nikita Bier), initially set for May 6 and later extended to May 30. The feature and its data, including member lists and post history, were removed with no archive, so the endpoints below no longer return live results. They remain documented as reference for legacy integrations. For any active work, use Lists (above).

X Communities were topic-based groups where users opted in to post and read within a dedicated space. Member rosters were a strong interest signal because membership was self-selected.

| Endpoint                      | Method | Returns                             | Page size |
| :---------------------------- | :----- | :---------------------------------- | :-------- |
| `/v3/community-members`       | POST   | Community member profiles           | \~20      |
| `/v3/community-tweets`        | POST   | Tweets posted inside the community  | \~20      |
| `/v3/community-search-tweets` | POST   | Keyword search inside the community | \~20      |

The Community ID is the numeric value in the community URL: `https://x.com/i/communities/1966045657589813686` means the ID is `1966045657589813686`.

Private Communities were not API-accessible.

### Get Community Members

`POST /v3/community-members`

| Parameter        | Type   | Required | Description               |
| :--------------- | :----- | :------- | :------------------------ |
| `community_link` | string | Yes      | Community ID or full URL. |
| `next_cursor`    | string | No       | Pagination cursor.        |

Returns compact member profiles (id, username, display name, avatar, verified, and protected status).

```python theme={null}
def get_community_members(community_link, max_pages=20):
    members, cursor = [], None

    for _ in range(max_pages):
        body = {"community_link": community_link}
        if cursor:
            body["next_cursor"] = cursor

        r = requests.post(
            f"{BASE}/community-members",
            headers={**HEADERS, "Content-Type": "application/json"},
            json=body,
            timeout=30,
        )
        r.raise_for_status()
        data = r.json()

        members.extend(data.get("users", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return members
```

### Get Community Tweets

`POST /v3/community-tweets`

| Parameter      | Type   | Required | Description                          |
| :------------- | :----- | :------- | :----------------------------------- |
| `community_id` | string | Yes      | Numeric Community ID.                |
| `order`        | string | No       | `"latest"` (default) or `"popular"`. |
| `next_cursor`  | string | No       | Pagination cursor.                   |

```python theme={null}
def get_community_tweets(community_id, order="latest", max_pages=10):
    tweets, cursor = [], None

    for _ in range(max_pages):
        body = {"community_id": community_id, "order": order}
        if cursor:
            body["next_cursor"] = cursor

        r = requests.post(
            f"{BASE}/community-tweets",
            headers={**HEADERS, "Content-Type": "application/json"},
            json=body,
            timeout=30,
        )
        r.raise_for_status()
        data = r.json()

        tweets.extend(data.get("tweets", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return tweets
```

### Search Community Tweets

`POST /v3/community-search-tweets`

| Parameter        | Type   | Required | Description                                             |
| :--------------- | :----- | :------- | :------------------------------------------------------ |
| `community_link` | string | Yes      | Community ID or full URL.                               |
| `query`          | string | No       | Search keyword. Omit to return the full community feed. |
| `order`          | string | No       | `"popular"` or `"latest"`.                              |
| `next_cursor`    | string | No       | Pagination cursor.                                      |

```python theme={null}
def search_community_tweets(community_link, query, order="popular", max_pages=5):
    tweets, cursor = [], None

    for _ in range(max_pages):
        body = {"community_link": community_link, "query": query, "order": order}
        if cursor:
            body["next_cursor"] = cursor

        r = requests.post(
            f"{BASE}/community-search-tweets",
            headers={**HEADERS, "Content-Type": "application/json"},
            json=body,
            timeout=30,
        )
        r.raise_for_status()
        data = r.json()

        tweets.extend(data.get("tweets", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break

    return tweets
```

For one-off membership checks (without paginating the full member list), use the dedicated [`/check-community-member`](https://docs.sorsa.io/api-reference/verification/check-community-membership) endpoint instead.

***

## Exporting to CSV

User and tweet feeds from the Lists endpoints above can be exported with a single helper. For users:

```python theme={null}
import csv

def export_users_to_csv(users, path):
    fields = ["id", "username", "display_name", "description",
              "followers_count", "tweets_count", "verified", "location"]

    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        for u in users:
            writer.writerow({
                "id": u.get("id", ""),
                "username": u.get("username", ""),
                "display_name": u.get("display_name", ""),
                "description": (u.get("description") or "").replace("\n", " "),
                "followers_count": u.get("followers_count", 0),
                "tweets_count": u.get("tweets_count", 0),
                "verified": u.get("verified", False),
                "location": u.get("location", ""),
            })


export_users_to_csv(get_list_members("1234567890"), "members.csv")
```

`/list-members`, `/list-followers`, and `/list-tweets` return full profiles, so every field above is populated. For tweets, swap the field list for `id`, `full_text`, `created_at`, `likes_count`, `retweet_count`, and `user.username`.

***

## Related

* [X List API guide](https://api.sorsa.io/blog/x-lists-and-communities-api): strategy, cost math, use cases
* [Real-Time Monitoring](https://docs.sorsa.io/real-time-monitoring): polling patterns for `/list-tweets`
* [Target Audience Discovery](https://docs.sorsa.io/target-audiences-Discovery): using lists for audience research
* [Marketing Campaign Verification](https://docs.sorsa.io/Marketing-Campaign-Verification): membership checks
* [Optimizing API Usage](https://docs.sorsa.io/optimizing-api-usage): request batching and rate-limit handling
