Last updated: May 16, 2026

Key Takeaway

The Twitter Search API lets developers query the public X timeline programmatically using keyword and operator-based filters. In 2026, the practical options are the official X API v2 /2/tweets/search/recent endpoint (pay-per-use, limited operators) and third-party scraping APIs that pass the full web search operator set through and bill on flat monthly plans.

The official Twitter search bar is fine when you are killing time. It is useless when you need to pull 50,000 tweets matching a complex Boolean query, run it on a schedule, push the results into a Postgres warehouse, and have someone in compliance audit the pipeline next quarter. That is what the Twitter Search API is for. This guide walks through how it works in 2026, the operators that actually fire, the code that handles real production traffic, and how the Sorsa API /search-tweets endpoint compares to the official X API for read-only search workloads.

I have been writing code against Twitter's search endpoints since the v1.1 era. Through the 2023 pricing overhaul, the v2 migration, and the 2025 shift to credit-based pay-per-use, the underlying mental model has not changed much: you send a query string, you get JSON back, you paginate with a cursor. What has changed is which provider you pay, how much you pay, and which operators silently get dropped before your query is executed. That last part trips up most people.

Table of Contents

  1. Why Search Tweets Programmatically?
  2. The Twitter Search API Landscape in 2026
  3. The /search-tweets Endpoint: Request Anatomy
  4. What's in the Response
  5. Search Operators That Actually Work
  6. Pagination: Collecting Thousands of Tweets
  7. Working Code: Python and JavaScript
  8. Real-World Query Templates
  9. Search Tweets vs. Track Mentions: Which Endpoint?
  10. How Sorsa Search Compares to the Official X API
  11. Common Errors and Troubleshooting
  12. Frequently Asked Questions
  13. Getting Started

Why Search Tweets Programmatically?

A search API exists because the use cases below cannot survive on manual browser refreshes:

Social listening and brand monitoring. Track every public mention of your product or competitors with structured JSON delivered into Slack, a dashboard, or an alerts pipeline. The signal is in the volume and the trend, not in any single tweet.

Competitor and market intelligence. Pull engagement-filtered tweets from your competitors' accounts, identify which posts performed, and build a content benchmark. Combine from:competitor min_faves:100 -filter:replies with date windows to compare quarter over quarter.

Sentiment analysis. Feed tweet text into a transformer model and score it. The search API gives you the raw text plus metrics (likes, replies, views) that double as confidence weights when aggregating sentiment. We covered the full pipeline in our Twitter sentiment analysis guide.

Lead generation. Searches like "looking for" (api OR tool) twitter surface people who are actively asking for what you sell. A well-crafted query is a free lead list.

Academic and journalistic research. Researchers need reproducible, auditable queries against a defined time window. A search endpoint with since: and until: is a primary data source.

Trend detection. Run the same query on a 5-minute cron, store the result counts, and detect spikes. This is how event-detection systems and crypto sentiment dashboards work under the hood.

The Twitter Search API Landscape in 2026

There is no single "Twitter Search API" anymore. There are three categories, and the spread between them on price and capability is wider than most developers realize.

The Official X API v2

Endpoint: /2/tweets/search/recent and /2/tweets/search/all. As of 2026, the X API runs on a credit-based pay-per-use model: each post read costs roughly $0.005, with separate pricing for owned reads and bulk discounts at higher commit levels. There is no free tier of any practical size for new accounts. Authentication uses OAuth 2.0 Bearer Tokens.

The harder problem is operator coverage. The official v2 endpoint accepts a much smaller subset of operators than the web search bar at x.com/search. Engagement filters that production teams rely on, including min_faves:, min_retweets:, min_replies:, and within_time:, are silently ignored if you include them in a v2 query. I have watched two clients build full pipelines on min_faves: filters before discovering this, then have to refactor.

The official archive search is available but priced for enterprise budgets. For most read-only research and monitoring workloads, the math does not work out.

Open-Source Scrapers

Twikit, TweeterPy, and XActions are still functional as of mid-2026. Twint is dead. twscrape and snscrape are broken in most setups. The maintained libraries work for small one-off jobs, but they sit on top of the public web search interface and break whenever X tweaks its frontend. None of them are realistic for production pipelines that need uptime guarantees.

Third-Party Search APIs

This is the category where Sorsa API sits, alongside platforms like TwitterAPI.io, GetXAPI, Apify, and others. These services run their own scraping infrastructure behind a clean REST API, expose the full web operator set, and charge predictable rates.

Our /search-tweets endpoint is the part of this guide we cover end to end. The reasoning for using it over the alternatives in this category comes down to four things: a flat monthly plan that does not multiply credits by endpoint type, the full web operator set passed through without silent drops, the same 20 requests per second rate limit across every plan, and authentication that is one header (ApiKey: YOUR_KEY) with no OAuth flow. For an end-to-end migration walkthrough off the official API, see our migration from the official X API docs.

If you want background on how X's pricing got here, our Twitter API pricing 2026 article walks through the timeline. For a broader survey of read-only alternatives, see our Twitter API alternative comparison.

The /search-tweets Endpoint: Request Anatomy

Send a POST request to:

POST https://api.sorsa.io/v3/search-tweets

Authentication is one header: ApiKey: YOUR_API_KEY (case-sensitive). No Bearer tokens, no OAuth dance, no callback URLs to register.

Request Body

ParameterTypeRequiredDescription
querystringYesSearch keywords. Supports the full set of native X search operators.
orderstringNo"popular" (default) matches the "Top" tab in X search. "latest" returns chronological, newest first.
next_cursorstringNoPagination cursor from a previous response. Omit on the first request.

Minimal cURL Example

bash
curl -X POST https://api.sorsa.io/v3/search-tweets \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "artificial intelligence",
    "order": "latest"
  }'

Why POST and Not GET?

Search queries get long. A real-world brand monitoring query can easily run past 200 characters once you add Boolean groupings, exclusions, language filters, and engagement thresholds. Putting them in a URL means URL-encoding every operator and praying the upstream proxy does not truncate. Putting them in a JSON body avoids the URL length and encoding problem entirely. This is also why the official v2 search endpoint moved most parameters out of query strings into request bodies for the bulk endpoints.

If you want to build queries visually before writing code, the Sorsa Search Builder renders the same operators as a form and outputs the query string you would paste into your script. The API Playground runs full requests against your key without writing any client code.

What's in the Response

The endpoint returns a JSON object with two top-level fields: an array of tweet objects and a pagination cursor.

json
{
  "tweets": [
    {
      "id": "2029914600217473314",
      "full_text": "The latest breakthroughs in AI are reshaping automation.",
      "created_at": "Fri Mar 06 13:38:49 +0000 2026",
      "lang": "en",
      "likes_count": 142,
      "retweet_count": 38,
      "reply_count": 12,
      "quote_count": 5,
      "view_count": 28400,
      "bookmark_count": 19,
      "is_reply": false,
      "is_quote_status": false,
      "conversation_id_str": "2029914600217473314",
      "entities": [],
      "user": {
        "id": "1422280682240450563",
        "username": "tech_insider",
        "display_name": "Tech Insider",
        "description": "Breaking tech news and analysis.",
        "followers_count": 84200,
        "verified": true
      }
    }
  ],
  "next_cursor": "DAABCgABGSmiaxkAAgoAAgjEJ..."
}

A few things matter here.

The full author profile ships inside every tweet. When I helped a hedge fund migrate off the official API in 2024, the single largest dev-time saving was not the price drop. It was not having to do a separate users/by/ids lookup for each tweet author. The official v2 endpoint requires you to add an expansions=author_id parameter and then walk through an includes.users array to match author IDs back to tweets. In our response, the user object is embedded directly. One request, both content and authorship.

Engagement metrics are not optional fields. Likes, retweets, replies, quotes, views, and bookmarks are always present on every tweet. No tweet.fields=public_metrics to remember.

next_cursor is the only pagination signal you need. When the field is a string, more results are available. When it is null or missing, you have reached the end of the result set.

For the complete field reference on Tweet and User objects, see response format.

Search Operators That Actually Work

The query field accepts the full set of native X search operators. Here is the working subset that covers 90% of real workloads. We have a separate deep-dive on the complete operator catalog at Twitter search operators; this section is the practical short list.

Keywords and phrases

  • artificial intelligence matches tweets containing any of these words
  • "artificial intelligence" matches the exact phrase
  • Word stemming is on by default: bear will also match bears

User-based

  • from:elonmusk tweets posted by an account
  • to:openai tweets replying to an account
  • @sorsa_app tweets mentioning an account

Engagement filters

  • min_faves:100 at least 100 likes
  • min_retweets:50 at least 50 retweets
  • min_replies:10 at least 10 replies

These three are the operators most worth knowing exist. They are also the ones the official X API v2 silently drops, so if you migrate code from a different provider you may see your "low quality" filter stop working without an error.

Content filters

  • filter:media, filter:images, filter:videos, filter:links
  • Prefix with - to exclude: -filter:retweets, -filter:replies, -filter:links

Language and date

  • lang:en (any ISO 639-1 code: es, fr, de, ja, and so on)
  • since:2026-01-01 on or after this date
  • until:2026-03-01 before this date (exclusive)

Boolean logic

  • (bitcoin OR ethereum) min_faves:100 lang:en parentheses for groups
  • crypto -scam -airdrop exclusion with a minus prefix

For the full operator set, including geo operators, source filters, card filters, and the language-code edge cases (lang:zxx for tweets with only media), see our search operators guide and the canonical community reference at igorbrigadir/twitter-advanced-search.

Pagination: Collecting Thousands of Tweets

A single search request returns one page of around 20 tweets. To pull larger datasets you use cursor-based pagination.

The logic is four steps:

  1. First request. Send query and order. Do not include next_cursor.
  2. Read the cursor. The response contains a next_cursor string.
  3. Next request. Send the same query, same order, plus the next_cursor value you just received.
  4. Repeat until next_cursor is null, empty, or absent.

This is more reliable than offset-based pagination because new tweets posted between your requests do not cause duplicates or skipped results. The cursor encodes a position in the result set, not a numeric offset.

Date-Range Chunking for Deep Pagination

There is one edge case worth knowing about before you trust a single cursor for 100,000 tweets.

On a market research project last year, I tried to pull 200,000 tweets matching bitcoin lang:en with a single cursor loop. Around page 70 the cursor started returning duplicates against earlier pages, and around page 90 it stopped advancing entirely. This is not specific to our API: any search index against a moving timeline has this property when you walk it deep enough.

The fix is to break the query into date-range chunks. Instead of one query over all time, run the same query for each week:

python
import datetime as dt
import time
import requests

API_KEY = "YOUR_API_KEY"
URL = "https://api.sorsa.io/v3/search-tweets"

def search_in_window(base_query, since, until, max_pages=50):
    """Paginate within a since/until window."""
    full_query = f"{base_query} since:{since} until:{until}"
    cursor = None
    out = []
    for _ in range(max_pages):
        body = {"query": full_query, "order": "latest"}
        if cursor:
            body["next_cursor"] = cursor
        resp = requests.post(
            URL,
            headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
            json=body,
        )
        resp.raise_for_status()
        data = resp.json()
        out.extend(data.get("tweets", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break
        time.sleep(0.1)
    return out

def search_chunked(base_query, start, end, days_per_chunk=7):
    """Walk a date range in chunks."""
    all_tweets = []
    cursor_date = start
    while cursor_date < end:
        next_date = min(cursor_date + dt.timedelta(days=days_per_chunk), end)
        chunk = search_in_window(
            base_query,
            cursor_date.strftime("%Y-%m-%d"),
            next_date.strftime("%Y-%m-%d"),
        )
        all_tweets.extend(chunk)
        print(f"{cursor_date} -> {next_date}: {len(chunk)} tweets")
        cursor_date = next_date
    return all_tweets

tweets = search_chunked(
    "bitcoin lang:en",
    dt.date(2026, 1, 1),
    dt.date(2026, 4, 1),
    days_per_chunk=7,
)

A weekly chunk on a noisy query like bitcoin lang:en typically yields a clean cursor walk to completion without dupe drift. For quieter queries you can stretch to monthly chunks. For very high-volume queries (think lang:en with no other filters) you may want daily.

For more on pagination patterns and rate-limit-aware retry logic, see pagination and our Twitter API rate limits 2026 article.

Working Code: Python and JavaScript

The examples below are what I run in production: cursor pagination, 429 backoff with exponential retries, and a small batching gap to respect the 20 req/s ceiling.

Python

python
import requests
import time

API_KEY = "YOUR_API_KEY"
URL = "https://api.sorsa.io/v3/search-tweets"

def search_tweets(query, order="popular", max_pages=5, max_retries=3):
    """
    Search tweets with cursor pagination and 429 backoff.

    Args:
        query: Search string (X operators supported).
        order: "popular" or "latest".
        max_pages: Maximum pages to fetch.
        max_retries: Retries on 429 before giving up on a page.

    Returns:
        List of tweet dicts.
    """
    all_tweets = []
    next_cursor = None

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

        for attempt in range(max_retries):
            resp = requests.post(
                URL,
                headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
                json=body,
            )
            if resp.status_code == 429:
                wait = 2 ** attempt
                print(f"Rate limited. Sleeping {wait}s.")
                time.sleep(wait)
                continue
            resp.raise_for_status()
            break
        else:
            print(f"Page {page + 1} failed after {max_retries} retries.")
            break

        data = resp.json()
        tweets = data.get("tweets", [])
        all_tweets.extend(tweets)
        print(f"Page {page + 1}: {len(tweets)} tweets (total {len(all_tweets)})")

        next_cursor = data.get("next_cursor")
        if not next_cursor:
            print("End of results.")
            break

        time.sleep(0.1)

    return all_tweets


# Usage
tweets = search_tweets('"Sorsa API" min_faves:5 lang:en', max_pages=10)
for t in tweets:
    u = t["user"]
    print(f"@{u['username']} ({u['followers_count']} followers)")
    print(f"  {t['full_text'][:120]}")
    print(f"  L:{t['likes_count']} RT:{t['retweet_count']} V:{t.get('view_count', 'N/A')}")

JavaScript (Node.js)

javascript
const API_KEY = "YOUR_API_KEY";
const URL = "https://api.sorsa.io/v3/search-tweets";

async function searchTweets(query, order = "popular", maxPages = 5, maxRetries = 3) {
  const allTweets = [];
  let nextCursor = null;

  for (let page = 0; page < maxPages; page++) {
    const body = { query, order };
    if (nextCursor) body.next_cursor = nextCursor;

    let data;
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      const resp = await fetch(URL, {
        method: "POST",
        headers: { "ApiKey": API_KEY, "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      if (resp.status === 429) {
        const wait = Math.pow(2, attempt) * 1000;
        console.log(`Rate limited. Sleeping ${wait}ms.`);
        await new Promise((r) => setTimeout(r, wait));
        continue;
      }
      if (!resp.ok) throw new Error(`API error: ${resp.status}`);
      data = await resp.json();
      break;
    }
    if (!data) break;

    const tweets = data.tweets || [];
    allTweets.push(...tweets);
    console.log(`Page ${page + 1}: ${tweets.length} tweets (total ${allTweets.length})`);

    nextCursor = data.next_cursor;
    if (!nextCursor) break;

    await new Promise((r) => setTimeout(r, 100));
  }

  return allTweets;
}

(async () => {
  const tweets = await searchTweets("bitcoin lang:en min_faves:50", "latest", 5);
  for (const t of tweets) {
    console.log(`@${t.user.username}: ${t.full_text.slice(0, 100)}`);
  }
})();

CSV Export Pipeline

A common downstream pattern is search to CSV, then load into a notebook or BI tool:

python
import requests, time, csv

API_KEY = "YOUR_API_KEY"
URL = "https://api.sorsa.io/v3/search-tweets"

def search_to_csv(query, order="popular", max_pages=10, out="tweets.csv"):
    fields = [
        "tweet_id", "created_at", "full_text", "lang",
        "likes", "retweets", "replies", "quotes", "views",
        "username", "display_name", "followers_count", "verified",
    ]
    with open(out, "w", newline="", encoding="utf-8") as f:
        w = csv.DictWriter(f, fieldnames=fields)
        w.writeheader()
        cursor, total = None, 0
        for _ in range(max_pages):
            body = {"query": query, "order": order}
            if cursor:
                body["next_cursor"] = cursor
            r = requests.post(
                URL,
                headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
                json=body,
            )
            r.raise_for_status()
            data = r.json()
            for t in data.get("tweets", []):
                u = t.get("user", {})
                w.writerow({
                    "tweet_id": t["id"],
                    "created_at": t["created_at"],
                    "full_text": t["full_text"],
                    "lang": t.get("lang", ""),
                    "likes": t.get("likes_count", 0),
                    "retweets": t.get("retweet_count", 0),
                    "replies": t.get("reply_count", 0),
                    "quotes": t.get("quote_count", 0),
                    "views": t.get("view_count", 0),
                    "username": u.get("username", ""),
                    "display_name": u.get("display_name", ""),
                    "followers_count": u.get("followers_count", 0),
                    "verified": u.get("verified", False),
                })
                total += 1
            cursor = data.get("next_cursor")
            if not cursor:
                break
            time.sleep(0.1)
        print(f"Exported {total} tweets to {out}")

search_to_csv(
    '(bitcoin OR ethereum) lang:en min_faves:10 -filter:retweets',
    order="latest",
    max_pages=20,
    out="crypto_tweets.csv",
)

At ~20 tweets per page, max_pages=50 gets you ~1,000 tweets. Combined with date-range chunking, you can scale this to six or seven figures without rewriting the loop.

Real-World Query Templates

Copy these, swap the variables, ship them.

Brand monitoring (organic mentions only)

("yourbrand" OR "@yourbrand") -from:yourbrand -filter:retweets lang:en

Catches what people say about you, excludes your own posts and retweets, English only. Run on a 5-minute cron, pipe into Slack.

Competitor content benchmark

(from:competitor1 OR from:competitor2 OR from:competitor3) min_faves:100 -filter:replies since:2026-01-01

Their top-performing original posts in the date window. Drop into a spreadsheet, sort by engagement, learn what works.

Sentiment tracking

(bitcoin OR $BTC) (bullish OR bearish OR moon OR crash OR pump OR dump) min_faves:20 lang:en

Sentiment-laden tweets above a quality floor. Pair with sentiment analysis for scoring.

Product feedback mining

"yourproduct" (bug OR broken OR issue OR love OR amazing OR hate) -filter:retweets

Organic feedback, both flavors. Useful for support and product roadmap input.

Lead generation

("looking for" OR "anyone recommend" OR "best tool for") (api OR scraping OR twitter data) -filter:retweets lang:en

People actively asking. Filter further by min_faves:1 to drop bot traffic.

Event reaction window

"product launch" OR "announcement" from:yourbrand since:2026-05-01 until:2026-05-08

Reactions to your own launch within a defined window. Pair from:yourbrand (your posts) with a separate query for the surrounding conversation.

Search Tweets vs. Track Mentions: Which Endpoint?

Two endpoints overlap on mention-tracking workloads. Which to pick:

/search-tweets is the general-purpose endpoint. Any operator combination, any query shape. Use it when you need flexibility, when your query is not just about one handle, or when you want to mix mentions with engagement filters in a single Boolean expression.

/mentions is purpose-built for tracking @-mentions of a single handle. It exposes the richest filter set in our API: min_likes, min_replies, min_retweets, since_date, until_date, all as first-class parameters instead of inline operators. Use it when your workflow is specifically "alert me on new mentions of @brand above X engagement."

Quick decision rule: if your query starts with @handle and ends with engagement filters, use /mentions. If it involves multiple terms, Boolean groups, or non-mention operators, use /search-tweets.

For a deep dive on the mentions endpoint and brand-monitoring workflows, see our Twitter mentions API guide (in progress) and the /mentions endpoint reference.

How Sorsa Search Compares to the Official X API

Disclosure: Sorsa API is our product. We have aimed to keep this comparison balanced and to recommend testing any solution against your own workload before committing.

DimensionSorsa /search-tweetsOfficial X API v2 /2/tweets/search/recent
Pricing modelFlat monthly plansPay-per-use, ~$0.005 per post read
AuthAPI key in ApiKey headerOAuth 2.0 Bearer Token
Account approvalInstant signupConsole signup, instant in 2026
Engagement operators (min_faves:, min_retweets:, min_replies:)YesSilently ignored
Web operator parityFull set passed throughSubset only
Author profile in responseEmbedded by defaultRequires expansions=author_id
Historical archiveBack to 2006Limited recent / archive on higher commit
Rate limit20 req/s, all plansCredit-based, varies
Real-time monitoringPolling at 20 req/sFiltered stream available

Where the official API still wins: filtered stream for true push-based real-time, and write actions (posting, liking, following) that we do not offer at all. For pure read-only search workloads, the operator silent-drop problem is the largest practical reason teams move off v2. For the broader migration picture see our migration guide and the official X search docs for current pricing and operator coverage.

Common Errors and Troubleshooting

Things that bite people, in rough order of how often I see them.

Empty results on a query you know should return something. Usual suspects: a typo in an operator (min_likes instead of min_faves), a phrase that needs double quotes ("black cat" not black cat), or a -filter: that excludes too much. Strip the query down to one keyword, confirm it returns results, then add operators back one at a time.

429 Too Many Requests. You exceeded 20 requests per second on the key. Back off for one second and retry. The Python and JavaScript examples above implement exponential backoff for this. The 20 req/s limit is universal across our plans; if you need higher throughput on a sustained basis, contact us about custom limits.

Cursor stops advancing or returns duplicates after deep pagination. This is the issue covered in the date-range chunking section. Any search index becomes unstable past a certain pagination depth on noisy queries. Switch to since:/until: weekly chunks.

Operator cap. X's search index appears to silently fail queries with more than approximately 22 to 23 operators. If your query has more groupings than that and returns empty, simplify it or split it into multiple requests.

user object is missing or partial. The author was suspended, deleted, or made their account protected between the time the tweet was created and the time you requested it. The tweet still exists in the index but the author is no longer publicly enumerable. Handle this with tweet.get("user", {}) defaults in your code.

Unexpected language results despite lang:en. Twitter's language detector is not perfect, especially on short tweets with hashtags or mixed scripts. For analytics workloads, post-filter with a language-detection library (such as langdetect or fasttext-langdetect) on the full_text field.

Private and shadow-banned accounts not appearing. Protected accounts are not in the search index. Suspended and locked accounts are also hidden. There is no operator to surface them. If shadow-banning is the question, our Twitter shadowban test tool can diagnose specific accounts.

Frequently Asked Questions

How do I search tweets without the official Twitter API?

Use a third-party search API or an open-source scraper. Third-party APIs (Sorsa, GetXAPI, TwitterAPI.io, Apify, and others) wrap their own scraping infrastructure behind a REST endpoint with an API key, no OAuth, and full web operator support. Open-source libraries like Twikit work for small one-off jobs but are not stable enough for production.

Can I search tweets older than 7 days?

Yes, on third-party APIs. The Sorsa /search-tweets endpoint supports the full historical archive going back to 2006 with since: and until: operators. The official X API v2 /2/tweets/search/recent is limited to ~7 days; full-archive search on the official API is restricted to higher-commit tiers.

How many tweets do I get per search request?

A single /search-tweets request returns one page of around 20 tweets. To pull more, use cursor pagination with next_cursor. For datasets above a few thousand tweets, combine cursor pagination with date-range chunking to avoid cursor drift on long walks.

What are the most useful Twitter search operators for developers?

The high-leverage operators in production code are from:, to:, min_faves:, min_retweets:, since:, until:, lang:, and the -filter:retweets / -filter:replies exclusions. Engagement filters (min_faves, min_retweets, min_replies) are particularly valuable because they remove low-quality noise without losing relevant content, and because they do not work on the official X API v2.

Does the Twitter Search API support Boolean logic (AND, OR, NOT)?

Yes. Space-separated terms imply AND. OR (uppercase) is explicit OR. Parentheses group expressions. A minus prefix excludes: crypto -scam. Example: (bitcoin OR ethereum) min_faves:100 -filter:retweets lang:en.

How much does it cost to search tweets via API in 2026?

The official X API v2 costs around $0.005 per post read on pay-per-use. Sorsa plans are flat monthly: $49 for 10,000 requests on Starter, $199 for 100,000 on Pro, $899 for 500,000 on Enterprise. At ~20 tweets per request, Pro yields roughly 2 million tweets per month at $0.0001 per tweet. See our Twitter API pricing 2026 article for the full pricing breakdown.

Can I search tweets in real time?

Practically yes through polling. With a 20 req/s rate limit and order: "latest", you can poll a query every few seconds and get new tweets within seconds of posting. For true push-based streaming, the official X API's filtered stream is the only option that delivers without polling. For most monitoring workloads, polling at 30-60 second intervals is sufficient and cheaper to operate. See our real-time monitoring docs for patterns.

Are deleted tweets searchable?

No. Once a tweet is deleted by the author or removed by X, it disappears from the search index. If you need to preserve tweets for compliance or research, capture them at collection time and store in your own database. The same applies to tweets from accounts that go private or get suspended after posting.

Getting Started

If you want to test the endpoint before writing code, the API Playground runs requests against your key from the browser. The Search Builder gives you a visual form for operators and outputs the JSON body you would send.

To pull an API key, sign up at the dashboard. For the five-minute setup walkthrough, see the quickstart. For the full schema and parameter reference, the API reference covers every endpoint.

For migration paths off the official API, the migration guide maps each v2 endpoint to its Sorsa equivalent with code examples on both sides.