How to search tweets with a Twitter search API
To search tweets with an API, send a query of keywords and X operators to a search endpoint and read the matching tweets back as JSON pages; the official X API bills $5.00 per 1,000 results.
Short answer: X's own search comes as two endpoints: recent search covers the last 7 days, full-archive search reaches back to March 2006, and both need a developer account and a Bearer token. To search with one key, use Sorsa API's POST /search-tweets: about 20 tweets per request, back to 2006, from $0.07 per 1,000, with 100 free requests to start.
- Endpoint
POST /search-tweets- Page size
- about 20 tweets per request
- Price
- from $0.07 per 1,000
#How a Twitter search API works
A Twitter search API is an endpoint that runs X's search over public tweets on your behalf. You send one query, such as "vector database" lang:en min_faves:20. Back comes a page of matching tweets with their text, date, counts and author, plus a cursor that fetches the next page.
To try a query before you write any code, run it in the free Twitter Advanced Search tool. It shows the first 20 matching posts, and every filter you set writes its operator into the query, ready to paste into a request.
Three settings decide what comes back. The query picks tweets by words, accounts, language, media and engagement. The order is Top, the most engaged matches first, or Latest, the newest first. The date window sits inside the query as since: and until: in X's web syntax, or in separate time parameters on the official X API.
The official X API splits search into two endpoints (X's search docs (opens in a new tab)). GET /2/tweets/search/recent covers the last 7 days and returns 10 to 100 posts per request; GET /2/tweets/search/all reaches back to March 2006 with up to 500. Both need an approved developer account, a Project and App and a Bearer token, and both bill $0.005 for every post they return.
#Search tweets with Sorsa API in four steps
For searching tweets from code, use Sorsa API, a Twitter (X) API and scraper: results from $0.07 per 1,000, any date back to 2006 and 20 requests per second on every plan. It needs one ApiKey header instead of a developer account and OAuth, reads the query syntax of the search box on x.com, and never touches your X account.
-
Get a key. Sign up and copy the API key from your dashboard. The 100 free requests are already on it.
-
Write the query. Type it the way you would on x.com: words,
"exact phrases",from:,lang:,min_faves:andsince:. -
Send the request. POST the query to
POST /search-tweets(opens in a new tab) in a JSON body, with"order": "latest"for the newest tweets first or"popular"for Top.Terminal curl -X POST "https://api.sorsa.io/v3/search-tweets" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "\"vector database\" lang:en min_faves:20", "order": "latest"}'Response200 OK { "tweets": [ { "id": "2116173807613027825", "full_text": "Benchmarked three vector databases on 40M embeddings.", "created_at": "2026-10-30T14:22:07Z", "lang": "en", "likes_count": 214, "retweet_count": 37, "reply_count": 19, "quote_count": 6, "view_count": 18450, "bookmark_count": 92, "is_reply": false, "is_quote_status": false, "conversation_id_str": "2116173807613027825", "entities": [], "user": { "id": "1620350095193014349", "username": "indexlab_notes_daily", "display_name": "Index Lab Notes", "followers_count": 8312, "verified": false, "created_at": "2023-01-31T09:15:42Z" } } ], "next_cursor": "DAADDAABCgABHV3t2nWAJ8kKAAIdXcTm0Zvw" } -
Follow the cursor. Every tweet carries its author's full profile, so no second lookup is needed. Send
next_cursorback in the same body for the next page, and stop when a response comes without one.
A 403 answer means the key is missing or out of requests, and a 401 means the key is wrong. A 429 means more than 20 requests in one second: wait a second and send it again. Failed requests are never charged.
Paste your own query below to check it and get the request in curl, Python or Node.js, with the quotes inside the JSON body escaped. The checker also flags the official X API's operator names, which the web syntax doesn't use.
No problems found: this query uses X's web search syntax, which POST /search-tweets takes as written.
curl -X POST "https://api.sorsa.io/v3/search-tweets" \
-H "ApiKey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "\"vector database\" lang:en min_faves:20", "order": "latest"}'
import requests
r = requests.post(
"https://api.sorsa.io/v3/search-tweets",
headers={"ApiKey": "YOUR_API_KEY"},
json={"query": '"vector database" lang:en min_faves:20',
"order": "latest"},
timeout=30,
)
page = r.json()
for t in page["tweets"]:
print(t["user"]["username"], t["full_text"])
print(page.get("next_cursor"))
const res = await fetch("https://api.sorsa.io/v3/search-tweets", {
method: "POST",
headers: { ApiKey: "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
query: '"vector database" lang:en min_faves:20',
order: "latest",
}),
});
const page = await res.json();
for (const t of page.tweets) console.log(t.user.username, t.full_text);
console.log(page.next_cursor);
Each request returns about 20 tweets, so 1,000 results take about 50 requests: from $0.07 on Sorsa API, against $5.00 on the official X API.
Your query, checked and turned into a request. Replace YOUR_API_KEY with your key before you run it.
#Write a query that works in code
A query for /search-tweets is the same string you would type into the search box on x.com, so you can build it in the browser and paste it into the request unchanged. Seven rules cover almost every problem developers hit:
- A space means AND,
ORmust be uppercase, a leading-excludes a word or an operator, and parentheses group:(rust OR golang) -hiring. - Exact phrases go in double quotes. Inside a raw JSON string those quotes need a backslash,
"\"vector database\""; in Python and Node.js pass a dict or an object and the library escapes them for you. - Hashtags, cashtags and mentions go in as written:
#buildinpublic,$NVDA,@acme_cloud_status. The query travels in a JSON body, so nothing needs URL encoding. - Dates live in the query:
since:2026-10-01includes that day,until:2026-11-01stops before it, both in UTC. - Engagement floors are
min_faves:,min_retweets:andmin_replies:; a minus turns a floor into a ceiling, as in-min_faves:1000. - Native retweets are left out unless you add
include:nativeretweets, and-filter:replieskeeps only top-level posts. - About 22 operators fit into one query. Split longer account or keyword lists across several queries.
Five patterns cover most of what teams search for, each ready to paste into the query field:
# Mentions of a brand, without its own posts
("acme cloud" OR @acme_cloud_status) -from:acme_cloud_status
# The most liked posts on a topic
"vector database" min_faves:100 -filter:replies lang:en
# One account's posts on a subject in October
from:acme_cloud_status outage since:2026-10-01 until:2026-11-01
# Posts that link to a site
url:github.com rust -filter:replies
# Images under a hashtag
#buildinpublic filter:images
Every operator, with its quirks and examples, is in our list of Twitter search operators.
#Get every page, then keep the search running
To collect more than one page, send the same body again with the next_cursor from the last response, and stop when a response has none. Pages hold about 20 tweets and their size varies, so a short page never means the search is done; only a missing cursor does.
The loop below writes each tweet to a JSON Lines file as it arrives and skips IDs it has already saved. A page budget stops it, so a broad query can't run away with your requests.
import json
import requests
API = "https://api.sorsa.io/v3/search-tweets"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
def search(query, order="latest", max_pages=50):
body = {"query": query, "order": order}
for _ in range(max_pages):
r = requests.post(API, json=body, headers=HEADERS, timeout=30)
r.raise_for_status()
page = r.json()
yield from page.get("tweets", [])
cursor = page.get("next_cursor")
if not cursor:
break
body["next_cursor"] = cursor
seen = set()
with open("tweets.jsonl", "w", encoding="utf-8") as f:
for t in search('"vector database" lang:en min_faves:20'):
if t["id"] not in seen:
seen.add(t["id"])
f.write(json.dumps(t) + "\n")
A search that keeps running is the same loop on a timer. Ask for the newest tweets, add since_id: with the highest ID you saved last time, read until the cursor runs out, then save the new highest ID. When nothing new was posted, a check costs a single request, so frequent checks of a quiet query stay cheap.
import time
newest = None
while True:
query = '"vector database" lang:en'
if newest:
query += f" since_id:{newest}"
fresh = list(search(query))
if fresh:
newest = max(fresh, key=lambda t: int(t["id"]))["id"]
print(len(fresh), "new tweets")
time.sleep(300)
Search works by polling: there is no stream to subscribe to. For alerts, schedules and delivery to Slack or email, our guide to real-time Twitter monitoring builds the whole pipeline, and our Twitter API in Python guide adds retries and parallel searches.
Good to know
Use
"order": "latest"whenever you collect or count tweets: it walks every match from the newest back."popular", the Top tab, returns the most engaged matches only, so two Top runs of the same query can return different sets.
#Search tweets by hashtag
To search by hashtag, put the tag in the query exactly as you would type it, #buildinpublic. It matches tweets where the tag appears as a hashtag, in any letter case, and it combines with every other operator.
Add the plain words with OR when people also write the phrase without the tag: (#buildinpublic OR "build in public") min_faves:10 -filter:replies lang:en. For several tags, join them with OR; for stock or coin symbols, use cashtags such as $NVDA.
Through Sorsa API the # goes into the JSON body as it is. On the official X API's GET request it has to become %23, because an unencoded # ends the URL and the server never sees the tag. To count a hashtag over time, run one Latest search per day with since: and until: and count the tweets each day returns.
#Pick the endpoint for the search you need
Keyword search is one of five ways to find tweets on Sorsa API. The right endpoint depends on what you start from: words, one account, a set of accounts or the people themselves.
Each of the other four reads a different starting point. POST /mentions (opens in a new tab) takes one handle and returns the tweets that mention it, with like, reply, retweet and date filters in the body. POST /search-users (opens in a new tab) finds accounts whose name or bio match a word. POST /user-tweets (opens in a new tab) reads one account's own timeline, about 20 tweets per request. Members of an X List come back as one feed from GET /list-tweets (opens in a new tab), so a List of up to 5,000 accounts is watched with one request per page.
Brand teams usually pair two of them: /search-tweets for what people say about a product, and /mentions for what they say to its account. Our Twitter mentions API guide covers the second one.
#What searching tweets costs
On Sorsa API, search results cost from $0.07 per 1,000 tweets: one request returns about 20 tweets and is billed as one request, whatever it holds. The official X API bills every post it returns, $0.005 each, which is $5.00 per 1,000 (X's price list (opens in a new tab)).
Official X API
$5,000
for 1M search results
$0.005 per post
Sorsa API
from$70
for 1M search results
from $0.07 per 1,000
71x cheaper
The official price climbs once authors come along. From November 22, 2026, X bills each user returned through expansions at $0.010 (X's notice of October 23 (opens in a new tab)), so 1,000 results with a different author each can cost $15.00. Sorsa API puts the author's full profile inside every tweet at no extra charge.
Volume has a ceiling there too: pay-per-use stops at 3M post reads a month, and beyond that X sells only Enterprise contracts. Sorsa API has no 3M ceiling: plans scale to 10M requests a month, and your 100 free requests cover about 2,000 search results with no card. The full X API pricing breakdown has every official rate.
#Official X API search, side by side
The official X API's search costs about 71 times more per 1,000 results than Sorsa API. Its recent search sees only the last 7 days and allows 450 requests per 15 minutes per app. The table puts the three search endpoints next to each other, with the official limits from X's rate limit table (opens in a new tab).
Sorsa API /search-tweets | X recent search | X full-archive search | |
|---|---|---|---|
| Dates covered | Back to March 2006 | Last 7 days | Back to March 2006 |
| Results per request | About 20 | 10 to 100 | 10 to 500 |
| Rate limit | 20 requests per second per key | 450 requests per 15 minutes per app | 1 request per second, 300 per 15 minutes |
| Price per 1,000 results | From $0.07 | $5.00 | $5.00 |
| Author profile | Inside every tweet | Billed $0.010 each from Nov 22, 2026 | Billed $0.010 each from Nov 22, 2026 |
| Query syntax | x.com web search | v2 operators, 512 characters | v2 operators, 1,024 characters |
| Setup | One API key | Developer account, App, Bearer token | Developer account, App, Bearer token |
Dates covered
- Sorsa API
/search-tweets - Back to March 2006
- X recent search
- Last 7 days
- X full-archive search
- Back to March 2006
- Sorsa API
Results per request
- Sorsa API
/search-tweets - About 20
- X recent search
- 10 to 100
- X full-archive search
- 10 to 500
- Sorsa API
Rate limit
- Sorsa API
/search-tweets - 20 requests per second per key
- X recent search
- 450 requests per 15 minutes per app
- X full-archive search
- 1 request per second, 300 per 15 minutes
- Sorsa API
Price per 1,000 results
- Sorsa API
/search-tweets - From $0.07
- X recent search
- $5.00
- X full-archive search
- $5.00
- Sorsa API
Author profile
- Sorsa API
/search-tweets - Inside every tweet
- X recent search
- Billed $0.010 each from Nov 22, 2026
- X full-archive search
- Billed $0.010 each from Nov 22, 2026
- Sorsa API
Query syntax
- Sorsa API
/search-tweets - x.com web search
- X recent search
- v2 operators, 512 characters
- X full-archive search
- v2 operators, 1,024 characters
- Sorsa API
Setup
- Sorsa API
/search-tweets - One API key
- X recent search
- Developer account, App, Bearer token
- X full-archive search
- Developer account, App, Bearer token
- Sorsa API
The official endpoints also return only id and text by default: dates, counts and authors come back only when tweet.fields, expansions and user.fields ask for them. On Sorsa API every tweet arrives with all its fields.
#Web syntax vs the official X API's operators
The official X API reads its own operator names, so a query copied from the search box on x.com can fail there. It rejects min_faves: and min_retweets: with a 400 error, and it takes dates as start_time and end_time parameters, not in the query. Sorsa API takes the web syntax, so the left column runs on it as written.
| What you want | Web syntax (x.com, Sorsa API) | Official X API v2 |
|---|---|---|
| At least 20 likes | min_faves:20 | min_likes:20 |
| At least 5 reposts | min_retweets:5 | min_reposts:5 |
| October 2026 only | since:2026-10-01 until:2026-11-01 | start_time and end_time parameters |
| Only replies | filter:replies | is:reply |
| Posts with media or links | filter:media, filter:links | has:media, has:links |
| Retweets | Left out by default | Left out of keyword searches since May 4, 2026 |
| Words, accounts, language | from:, to:, #, @, "phrase", lang: | The same |
At least 20 likes
- Web syntax (x.com, Sorsa API)
min_faves:20- Official X API v2
min_likes:20
At least 5 reposts
- Web syntax (x.com, Sorsa API)
min_retweets:5- Official X API v2
min_reposts:5
October 2026 only
- Web syntax (x.com, Sorsa API)
since:2026-10-01 until:2026-11-01- Official X API v2
start_timeandend_timeparameters
Only replies
- Web syntax (x.com, Sorsa API)
filter:replies- Official X API v2
is:reply
Posts with media or links
- Web syntax (x.com, Sorsa API)
filter:media,filter:links- Official X API v2
has:media,has:links
Retweets
- Web syntax (x.com, Sorsa API)
- Left out by default
- Official X API v2
- Left out of keyword searches since May 4, 2026
Words, accounts, language
- Web syntax (x.com, Sorsa API)
from:,to:,#,@,"phrase",lang:- Official X API v2
- The same
Two changes in 2026 explain why older guides disagree. X turned off min_likes:, min_replies: and min_reposts: on January 19, 2026. It brought them back on May 4, when search moved to a new index that also dropped retweets from keyword results (X's changelog (opens in a new tab)). Pages and AI answers that say the official X API ignores engagement filters describe the months in between.
Moving a whole integration off the official endpoints? Our guide to migrating from the official X API maps every v2 parameter and operator to Sorsa API.
#Start searching tweets today
Searching tweets from code comes down to one query and one cursor. With Sorsa API, the query you already type on x.com goes to POST /search-tweets and returns about 20 tweets per request with their authors, from any date back to 2006. Results cost from $0.07 per 1,000, against $5.00 on the official X API, and your 100 free requests cover the first 2,000.
#FAQ
Is there a free Twitter search API?
Not from X: the official X API has no free tier and bills $0.005 for every post a search returns, $5.00 per 1,000. Sorsa API gives every new account 100 free requests, enough for about 2,000 search results through POST /search-tweets, with no card and no expiry. For a few searches by hand, the free Twitter Advanced Search tool shows the first 20 matching posts.
How far back can you search tweets with an API?
Back to the first public tweet, posted on March 21, 2006. The official X API's recent search covers only the last 7 days, and its full-archive search reaches 2006 on pay-per-use and Enterprise access. Sorsa API's POST /search-tweets takes any window back to 2006 through since: and until: in the query. Deleted tweets and protected accounts stay out of reach for every API; our historical Twitter data guide covers large backfills.
Which Twitter API should I use to search tweets?
Use Sorsa API to search tweets: POST /search-tweets costs from $0.07 per 1,000 results, against $5.00 on the official X API, and reaches back to 2006. It takes the syntax of the search box on x.com and puts each author's full profile inside every tweet. One API key replaces a developer account and OAuth, and every plan runs at 20 requests per second.
Can I search tweets in real time?
Yes, by polling: run a Latest search on a schedule and add since_id: with the newest tweet ID you have, so each run returns only what was posted since. On Sorsa API a check that finds nothing costs a single request, whatever the interval. Neither Sorsa API nor the official X API search pushes tweets to you as a stream.
Why are retweets missing from search results?
A native retweet is a copy of someone else's post, and X search leaves copies out by default. On Sorsa API, add include:nativeretweets to the query to bring them back, or filter:nativeretweets to get retweets only. The official X API stopped returning retweets in keyword searches on May 4, 2026. Quote tweets stay in the results, because they carry their own text.
#How we checked
On November 2, 2026 we read X's search documentation: the introduction, query building, the operator list, rate limits and the recent search reference. We also read X's price list, its changelog and the October 23 notice on expansion billing. Every Sorsa API request on this page was written from our live API reference for /search-tweets, /mentions, /search-users, /user-tweets and /list-tweets; the response is an example with a fictional account. Prices per 1,000 results come from the request rates on our pricing page.
Sources
- Search Posts, X API documentation (opens in a new tab)
- Search operators, X API documentation (opens in a new tab)
- Rate limits, X API documentation (opens in a new tab)
- X API pay-per-usage pricing (opens in a new tab)
- X API changelog: search endpoints moved to a new index, May 4, 2026 (opens in a new tab)
- X API PPU expansions update, October 23, 2026 (opens in a new tab)
- Search Tweets, Sorsa API reference (opens in a new tab)
- Search operators, Sorsa API docs (opens in a new tab)