Updated June 2026: refreshed the X Communities status after the platform's retirement announcement, added a response field reference for the List endpoints, and corrected the monthly request math in the cost section.
Key Takeaway An X List is a public, curated group of up to 5,000 accounts with its own timeline. A List API returns every member, every subscriber, and a combined tweet feed from those members in single calls. Polling one List replaces polling each account, cutting request volume by roughly 50 times for a 50-account watchlist.
X Lists are one of the most underused data sources on the platform. A well-maintained List is a hand-curated roster: an analyst's set of fintech founders, a journalist's set of war reporters, an exchange's set of crypto KOLs. Someone has already done the audience research, and the resulting List is queryable as a single object.
The endpoints behind that workflow used to live only in the official X API, which is workable if you are comfortable with OAuth 2.0, monthly post-read quotas, and pricing that does not scale for continuous monitoring. Sorsa API, an alternative Twitter/X API, exposes Lists through three endpoints behind a single ApiKey header: no OAuth, no app review, and a flat 20 requests per second on every plan starting at $49 for 10,000 requests. The /list-members endpoint returns up to 200 profiles per request, so the patterns below stay cheap at scale. The strategic points (what to query, when a List beats raw polling, how to think about cost) are general, and the code is plain Python you can run as written.
Table of contents
- What is an X List, and what can you pull from it?
- Why poll a List instead of each account?
- The three List endpoints
- What does the List API return?
- What are X Lists good for beyond monitoring?
- A note on X Communities
- Twitter List API vs the official X API
- How to set up a List you can monitor
- Code: pulling List data in Python
- What this looks like in practice
- Getting started
- FAQ
What is an X List, and what can you pull from it?
An X List is a public or private collection of up to 5,000 accounts with its own timeline showing only posts from its members. Anyone can create one, and anyone with access can subscribe to it. Through an API you can extract two different audiences from a public List: its members and its subscribers.
Those two groups signal different things, and both are extractable:
- Members are the accounts on the List. They are who the curator thought was worth tracking.
- Subscribers (followers of the List) are users who chose to follow the List to read it. They actively opted into that topic.
Private Lists are not reachable through any API, official or third party. Everything below assumes the List is public and resolves when opened in a logged-out browser.
Why poll a List instead of each account?
Polling a List collapses many per-account requests into one. The reason Lists matter for engineering, not just curation, is request volume.
Suppose you track 50 accounts, say a fintech sector watchlist, and poll each one every 10 seconds. That is 50 requests per cycle, 8,640 cycles per day, and 432,000 requests per day, roughly 13 million a month. No plan on any provider is built for that.
Build a List of the same 50 accounts and poll a single tweet feed instead. One request per cycle at the same 10-second interval is 8,640 requests per day, about 259,000 a month. You catch the same posts, often with lower latency, because List timelines are cached aggressively on X's side.
| Approach | Requests per cycle | Per day (10s poll) | Per month (10s poll) |
|---|---|---|---|
| Per-account timeline pulls, 50 accounts | 50 | 432,000 | ~13,000,000 |
| Single List feed call | 1 | 8,640 | ~259,000 |
One List call replaces 50 per-account calls, a 50x reduction that scales with the watchlist: a 200-account List is a 200x reduction.
In practice you rarely need a 10-second cadence. Polling one List every 30 seconds is about 86,000 requests a month, which sits comfortably inside Sorsa's Pro plan at $199 for 100,000 requests. This is the dominant pattern in the real-time monitoring pipelines we set up with customers running social listening.
The three List endpoints
Sorsa exposes three List endpoints, all paginated through next_cursor. When the cursor comes back null or absent, you have reached the end.
| Endpoint | Returns | Per request | Best use |
|---|---|---|---|
GET /v3/list-members | Member profiles | up to 200 | Audience extraction, List audits |
GET /v3/list-followers | Subscribers to the List | up to 200 | Discover people interested in a topic |
GET /v3/list-tweets | Combined feed from members | up to 20 | Monitoring, content and sentiment analysis |
For audience research, /list-followers is often more useful than /list-members: members are who the curator picked, while subscribers self-identified as interested in the topic. If you also need each account's own follower and following graph, that is a separate job covered by the follower and following lists endpoints, not the List endpoints here.
What does the List API return?
The List endpoints return clean JSON with no separate billing for the nested author profile. /list-members and /list-followers return a users array of full profile objects plus a next_cursor. /list-tweets returns a tweets array plus a next_cursor, and every tweet carries its full author profile inline at no extra cost.
These are the main fields on each member or subscriber profile object:
| Field | Type | Meaning |
|---|---|---|
id | string | Stable numeric user ID |
username | string | Handle without the @ |
display_name | string | Profile display name |
description | string | Bio text |
location | string | Location from the profile |
followers_count | integer | Number of followers |
followings_count | integer | Accounts the user follows |
tweets_count | integer | Total posts |
verified | boolean | Verified badge |
protected | boolean | Private account |
created_at | string | Account creation date (ISO 8601) |
bio_urls | array | URLs found in the bio |
Each tweet in a /list-tweets response carries text, metrics, and the author. The main fields:
| Field | Type | Meaning |
|---|---|---|
id | string | Tweet ID |
full_text | string | Full post text |
created_at | string | Publication date (ISO 8601) |
lang | string | Detected language code |
likes_count | integer | Likes |
retweet_count | integer | Retweets |
reply_count | integer | Replies |
quote_count | integer | Quote posts |
view_count | integer | Views |
is_reply | boolean | Whether the post is a reply |
is_quote_status | boolean | Whether it quotes another post |
user | object | Full author profile (same fields as above) |
entities | array | Attached media and links |
A trimmed /list-tweets response looks like this:
{
"tweets": [
{
"id": "1782368585664626774",
"full_text": "Shipping the new pricing today.",
"created_at": "2026-05-18T10:30:00Z",
"lang": "en",
"likes_count": 200,
"retweet_count": 50,
"reply_count": 10,
"view_count": 10000,
"is_reply": false,
"is_quote_status": false,
"user": {
"id": "44196397",
"username": "founder",
"display_name": "A Founder",
"followers_count": 100000,
"verified": true,
"created_at": "2009-06-02T20:12:29Z"
},
"entities": []
}
],
"next_cursor": "DAABCgAB..."
}
Because the author profile is embedded in every tweet, a single List feed call gives you both content and the people behind it, with no second lookup and no per-profile charge. Full field definitions are in the Lists and Communities documentation.
What are X Lists good for beyond monitoring?
Beyond real-time monitoring, Lists support several research patterns that would otherwise take far more work:
Niche expert discovery. Journalists and analysts curate Lists with names like "AI Safety Researchers" or "DeFi Founders." The member roster is an expert-vetted shortlist. Pull it once, sort by follower count or recent engagement, and you have an outreach target list in minutes.
Audience overlap analysis. Pull members of two competing Lists in the same niche. The intersection shows the consensus picks; the difference shows each curator's blind spots. It is faster than running competitor analysis from scratch.
Sector sentiment. Pull a 100-account industry List's feed daily, push the text through any sentiment model, and plot the rolling average. You get a signal without doing any account discovery first.
Audience inheritance. Pull the subscribers of an industry List maintained by a respected curator. These are people who opted into the topic, a much cleaner lead pool than a generic follower scrape.
A note on X Communities
X Communities are topic-based, opt-in groups: members choose to join, which makes the roster a strong interest signal rather than a curator's pick. Sorsa exposes them through /community-members, /community-tweets, and /community-search-tweets, all POST endpoints that follow the same pagination pattern as the List endpoints.
A status note matters here. X announced in April 2026 that it planned to retire Communities, citing usage under 0.4% of accounts and a disproportionate share of platform spam, as TechCrunch reported alongside an extension of the original deadline. The timeline has since moved, and as of June 2026 Communities and the Community endpoints still return data. Treat the feature as at risk: if you build anything durable, build it on Lists, which are not slated for removal. If you need to extract a Community now, the pattern is identical to the List code below, using POST with community_id or community_link.
Twitter List API vs the official X API
The official X API does expose List endpoints. Which one to use depends mostly on how much volume you need and how much OAuth you are willing to maintain. Sorsa API is our product, and the comparison below uses figures you can verify in X's developer documentation and our own X API pricing breakdown. Test any provider against your own workload before committing.
| Sorsa API | Official X API | |
|---|---|---|
| Authentication | Single ApiKey header | OAuth 2.0 or Bearer, app review |
| Setup time | Minutes (sign up, get key) | Days to weeks (app approval) |
| List members per page | Up to 200 | Up to 100 (v2) |
| Rate limit | Flat 20 req/s on every plan | Per-endpoint, 15-minute windows |
| Billing model | Flat per request (1 call = 1 request) | Per resource fetched, pay-per-use |
| Entry pricing | $49/mo for 10,000 requests | Pay-per-use, no flat List tier |
| Write access | None (read-only) | Posting and DMs (follow, like, quote are Enterprise-only since April 20, 2026) |
| Communities | Yes (at risk, see note above) | Yes, limited |
If you need write access, official first-party status, or filtered streaming, that is the official X API's territory. For read-heavy List extraction at a flat, predictable price with no approval queue, Sorsa is the fit, and on read-heavy workloads it runs roughly 30 to 50 times cheaper. The per-request model also means the embedded author profiles in a List feed cost nothing extra, where the official API bills each user read separately. The rate-limit teardown covers why per-endpoint windows hurt continuous monitoring.
How to set up a List you can monitor
You can only pull data from Lists that exist, and every API on this point is read-only. To set up a List you can monitor, do it once in the X web interface:
- Go to x.com/lists and select "Create new list."
- Mark the List public. Private Lists are not API-accessible by anyone.
- Add up to 5,000 accounts. You can paste handles, search, or import in bulk.
- Copy the numeric List ID from the URL: in
https://x.com/i/lists/1234567890, the ID is1234567890. - Poll the List feed against that ID at whatever interval your latency budget allows.
The List does not have to be yours to be queryable. If someone else's public List already covers your topic, grab the ID from their URL. If you are building a private monitoring pipeline and do not want your tracked accounts visible under your main identity, create the List under a separate account with a generic name; it stays public so the API can reach it, but it is not tied to your real handle.
Code: pulling List data in Python
The examples use plain Python with requests. No SDK, no auth dance. They assume Python 3.9 or newer and an API key in an environment variable. Every paginated endpoint returns next_cursor; when it is null or missing, you are done.
import os
import time
import requests
API_KEY = os.environ["SORSA_API_KEY"]
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY}
Extracting List members
def get_list_members(list_id, max_pages=50):
"""Fetch member profiles from a public X List. Up to 200 per page."""
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
time.sleep(0.1)
return members
members = get_list_members("1234567890")
print(f"Pulled {len(members)} members")
for m in members[:5]:
bio = (m.get("description") or "")[:60]
print(f"@{m['username']} ({m['followers_count']:,} followers): {bio}")
A fully populated 5,000-member List takes about 25 requests to extract, since the endpoint returns up to 200 profiles per call.
Extracting List subscribers
Subscribers (people who follow the List to read it, not the members on it) use the list_link parameter, which accepts either the full URL or just the numeric ID.
def get_list_followers(list_link, max_pages=50):
"""Users who subscribe to a public X List."""
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
time.sleep(0.1)
return followers
subs = get_list_followers("https://x.com/i/lists/1234567890")
print(f"{len(subs)} accounts subscribe to this List")
Pulling tweets from a List
This is the monitoring endpoint: about 20 tweets per call, sorted chronologically across all members.
def get_list_tweets(list_id, max_pages=10):
"""Recent tweets from all members of a List, combined feed."""
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
time.sleep(0.1)
return tweets
feed = get_list_tweets("1234567890", max_pages=20)
print(f"Collected {len(feed)} tweets")
for t in feed[:5]:
likes = t.get("likes_count", 0)
print(f"@{t['user']['username']} ({likes} likes): {t['full_text'][:80]}")
For continuous monitoring, run this on a cron or asyncio loop at whatever interval suits your latency budget. Polling every 30 to 60 seconds is plenty for everything short of trading signals.
Exporting to CSV
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", ""),
})
print(f"Wrote {len(users)} rows to {path}")
export_users_to_csv(get_list_members("1234567890"), "members.csv")
The same pattern works for subscribers. For tweets, swap the field list for id, full_text, created_at, likes_count, retweet_count, and user username.
Retry and rate-limit handling
Anything you run on a schedule needs minimal error handling. The flat Sorsa rate limit is 20 requests per second. If you exceed it, you get a 429; back off and retry.
def request_with_retry(method, url, max_attempts=5, **kwargs):
for attempt in range(max_attempts):
r = requests.request(method, url, **kwargs)
if r.status_code == 429:
time.sleep(2 ** attempt)
continue
if r.status_code >= 500:
time.sleep(1 + attempt)
continue
r.raise_for_status()
return r
raise RuntimeError(f"Failed after {max_attempts} attempts: {url}")
Drop this in place of requests.get in any function above. For long-running jobs, log the cursor between pages so you can resume on failure without redoing work. More patterns are in optimizing API usage.
What this looks like in practice
A small analytics team we worked with, around ten people building signals for a trading desk, was monitoring roughly 120 crypto KOLs by polling each account on its own. The per-account approach was both expensive on the official API and slow to react. Moving the same accounts into a single public List and polling one feed cut the request volume dramatically and gave them an earlier read on shifting tone than waiting for aggregated third-party sentiment trackers. The cost side followed the general pattern any read-heavy team sees switching off the official API: data costs dropped by roughly 30 to 50 times for the same coverage. The win was structural, not a trick: one List feed instead of 120 timelines.
Getting started
Grab an API key from the Sorsa dashboard, point it at a List you already follow on X, and you are collecting structured data within a few minutes. The API Playground lets you test every endpoint without writing code first, and the pricing plans start at $49 for 10,000 requests with the same flat 20 requests per second on every tier. If you are moving off the official X API and want an endpoint-by-endpoint map, the migration guide walks through the equivalences.
FAQ
Can you extract members from a private X List?
No. Private X Lists are not accessible through any API, official or third party. The List must be public, and its URL must resolve when opened in a logged-out browser. Anyone claiming to pull private List data is either mistaken or planning to misuse a logged-in account. Everything described in this guide assumes a public List.
What is the maximum X List size you can extract?
X caps Lists at 5,000 members. The Sorsa list-members endpoint paginates at up to 200 profiles per request, so a full 5,000-member List takes about 25 calls to extract end to end. There is no hidden ceiling beyond the 5,000-member platform limit itself.
How do you find a List ID from its URL?
X List URLs look like https://x.com/i/lists/1234567890, where the numeric value at the end is the List ID. Some older URLs use the form x.com/username/lists/slug; opening that link redirects to the numeric version, and the number in the resulting URL is the ID you pass to the API.
Do X Communities still work through the API?
As of June 2026, yes. X announced in April 2026 that it planned to retire Communities, citing low usage and high spam, and the initially announced cutoff has since moved, but the feature and the Community endpoints still return data. Treat Communities as at risk and build durable monitoring on Lists, which are not slated for removal.
Is polling a List more efficient than calling the API once per account?
Yes, and this is the main reason Lists matter for engineering. Building one public List and polling a single tweet feed replaces one request per account per cycle. For a 50-account watchlist on Sorsa, that is roughly 50 times fewer requests than polling each account separately, and the saving scales with the number of accounts on the List.
Can you get historical tweets from a List, not just recent ones?
A List tweet feed returns the recent combined timeline of its members, going back as far as that timeline is available. For deep history on a specific account, pull that account's own timeline instead; on Sorsa the user-tweets endpoint paginates back to an account's earliest posts with no 3,200-tweet cap. Lists are for monitoring, per-account pulls are for archives.
How much does pulling List data cost compared with the official X API?
Sorsa bills a flat one request per API call regardless of how many profiles or tweets come back, starting at $49 for 10,000 requests. The official X API bills per resource fetched under pay-per-use, so a single List read that returns many users and tweets is charged per item. On read-heavy List workloads Sorsa runs roughly 30 to 50 times cheaper.
Do List IDs from the old Twitter v1.1 era still work?
Yes, as long as the List is still public and loads on the web. List IDs created in the Twitter v1.1 days remain valid on the current X platform and on third-party APIs like Sorsa. The Twitter to X rebrand did not invalidate existing List IDs or change their numeric format.
Reviewed by Keksich, founder of Sorsa, marketer and X API researcher.
This guide draws on our team's hands-on work operating Sorsa's List and Community endpoints, the live Sorsa API v3 documentation, and X's own developer documentation. The X Communities retirement timeline is sourced from TechCrunch; Community availability was checked directly on X. Pricing and rate-limit comparisons were re-verified against our 2026 X API pricing guide and the official X developer pricing pages. Last verified June 13, 2026.