Skip to main content

Extract members, tweets, and followers from X Lists and Communities via the Sorsa API.

X Lists and X Communities are two ways to organize groups of accounts on the platform. Sorsa API provides endpoints to extract members, tweets, and followers from both. This page is the endpoint reference.
Note: For strategic context, cost math, and end-to-end monitoring workflows, see the X List API guide on the blog.
X Communities deprecation notice X is shutting down Communities on May 30, 2026 (announced by head of product Nikita Bier in April 2026). The three Community endpoints below continue to work until that date and are kept here for completeness. Use Lists for any new monitoring 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.
EndpointMethodReturnsPage size
/v3/list-membersGETUser profiles of accounts in the listup to 200
/v3/list-followersGETUser profiles of accounts following the listup to 200
/v3/list-tweetsGETCombined chronological feed from list members~20
The List ID is the numeric value in the list URL: https://x.com/i/lists/1234567890 → ID is 1234567890.

Get List Members

GET /v3/list-members
ParameterTypeRequiredDescription
list_idstringYesNumeric List ID.
next_cursorintegerNoPagination cursor from a previous response.
curl "https://api.sorsa.io/v3/list-members?list_id=1234567890" \
  -H "ApiKey: YOUR_API_KEY"
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
ParameterTypeRequiredDescription
list_linkstringYesList URL or numeric ID.
next_cursorstringNoPagination cursor.
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 workflow for tracking groups of accounts with a single request instead of polling each account separately.
ParameterTypeRequiredDescription
list_idstringYesNumeric List ID.
next_cursorstringNoPagination cursor.
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

Communities will be discontinued on May 30, 2026. The endpoints below remain available until that date.
X Communities are topic-based groups where users opt in to post and read within a dedicated space. Member rosters are a strong interest signal because membership is self-selected.
EndpointMethodReturnsPage size
/v3/community-membersPOSTCommunity member profiles~20
/v3/community-tweetsPOSTTweets posted inside the community~20
/v3/community-search-tweetsPOSTKeyword search inside the community~20
The Community ID is the numeric value in the community URL: https://x.com/i/communities/1966045657589813686 → ID is 1966045657589813686. Private Communities are not API-accessible.

Get Community Members

POST /v3/community-members
ParameterTypeRequiredDescription
community_linkstringYesCommunity ID or full URL.
next_cursorstringNoPagination cursor.
curl -X POST https://api.sorsa.io/v3/community-members \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"community_link": "1966045657589813686"}'
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
ParameterTypeRequiredDescription
community_idstringYesNumeric Community ID.
orderstringNo"latest" (default) or "popular".
next_cursorstringNoPagination cursor.
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
ParameterTypeRequiredDescription
community_linkstringYesCommunity ID or full URL.
querystringYesSearch keyword.
orderstringNo"popular" or "latest".
next_cursorstringNoPagination cursor.
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 endpoint instead.

Exporting to CSV

User and tweet feeds from any of the endpoints above can be exported with a single helper. For users:
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")
For tweets, swap the field list for id, full_text, created_at, likes_count, retweet_count, and user.username.