XAnswer

Is the Twitter API free? What X charges to read posts and followers

No. X's API is pay-per-use: $0.005 per post read, $0.01 per follower. 1,000 posts cost $5 on X. One-time credits and a tested script for X data.

8 min read

Short answer

  • No. X's API has no free plan today, except free access for apps X classes as Public Utility Apps. It is pay-per-use: $0.005 per post read and $0.010 per user or follower read (docs.x.com, read 2026-10-16).
  • New accounts can get one-time credits: $20 for saving a first card, plus a match of the first auto-recharge up to $50, which you pay first. X staff retired the fixed Basic plan (2026-05-21 notice) and Pro plan (2026-08-14 notice).
  • ToolzerHub returns public X posts, search results and follower lists as JSON. 1,000 posts cost 250 credits and 1,000 followers 15 credits: $0.25 to $0.48 and $0.015 to $0.029. 100 free credits a month.
On this page

X's API is not free. It has no free plan today, apart from free access for apps X classes as Public Utility Apps: it bills per resource returned, $0.005 per post read and $0.010 per user or follower read, with no subscription. New accounts can get up to $70 in one-time credits, but $50 of that matches money you pay in first. We read X's documentation on 2026-10-16.

What X charges to read

X bills reads per resource returned. X's pricing page opens: "The X API uses pay-per-usage pricing. No subscriptions—pay only for what you use." Reads are "Charged per resource returned in the response."

Read Price per resource
Posts $0.005
User $0.010
Following and followers $0.010
Your own posts, followers or bookmarks ("Owned Reads") $0.001

The page also says "Pay-per-usage plans are capped at 3 million Post reads per monthly billing cycle", and that asking for the same resource again within a 24-hour UTC day is charged once. It lists no separate search price. A search returns posts, so we count each one as a Post read. X adds that prices are subject to change and that its Developer Console shows current rates.

Is there still a free tier?

X's pricing page shows no free plan, and X retired its fixed plans in stages:

  • 2026-02-06, changelog: "Public Utility Apps continue to receive free scaled access. Recently active Legacy Free tier users receive a one-time $10 voucher. Basic and Pro plans remain available, and existing subscribers can opt in to Pay-Per-Use."
  • 2026-02-13, an X staff reply in the developer forum: "Legacy packages like Free, Basic, and Pro have been deprecated."
  • 2026-05-21, X staff: "Our legacy Basic plans (both monthly and annual) are being deprecated."
  • 2026-08-14, X staff: "Our legacy Pro plans (both monthly and annual) are being deprecated." Pro subscriptions end at the first billing cutover after September 1, 2026.

The changelog line saying Basic and Pro "remain available" has not been updated. X's Developer Guidelines still mention a "free tier" that is "non-commercial only", but the pricing page prints no Free plan and no limits for one, so we don't repeat the 500 or 1,500 posts a month that older write-ups list.

What the free credits buy

A new account can get up to $70 in one-time credits, which is 14,000 post reads. X gives $20 when you save your first eligible credit or debit card, and matches your first auto-recharge up to $50, so that part needs you to pay in first. The credits "expire 3 months after they are granted". X also says the incentives are "currently rolling out": until they are enabled for your account, saving a card issues no credit.

At the prices above, the $70 is 14,000 post reads or 7,000 follower reads (our arithmetic). Apps X classifies as Public Utility Apps get free scaled access.

Limits for search, posts and followers on X

The limits are rate limits plus your credit balance; X says they are separate. From X's rate-limit table and endpoint references (read 2026-10-16):

  • Recent search: posts from the last 7 days, 100 posts per request, 450 requests per 15 minutes per app.
  • A user's posts: up to 100 per request.
  • Followers: up to 1,000 per request, 300 requests per 15 minutes, $0.01 each. We priced a full export in the Twitter API followers list.

Read X posts and followers with ToolzerHub

We make ToolzerHub. Our X API returns public posts, search results and follower lists as JSON with one API key and no X developer account. Credits per call, from our OpenAPI file on 2026-10-16: profile 1, profile posts 5, search 5, followers 3.

We ran 10 hand-run calls that day on NASA, GitHub, BBCWorld and nytimes. All 10 returned data. A posts call returned 20 posts, a search 19 or 20, a followers call 200 profiles, and each came with a cursor for the next page. The script below follows the cursor and writes posts to CSV. Give it handles, or search: plus a query.

python
import csv
import os
import sys
import time

import requests

BASE = "https://api.toolzerhub.com/v1/x"
HEADERS = {"x-api-key": os.environ["TOOLZERHUB_API_KEY"]}
FIELDS = ["source", "post_id", "handle", "posted", "likes", "replies", "reposts", "quotes",
          "views", "bookmarks", "text", "url"]
calls = 0


def cell(value):
    # Spreadsheets run text that starts with = + - or @ as a formula; an apostrophe keeps it text.
    if isinstance(value, str) and value[:1] in ("=", "+", "-", "@", "\t", "\r"):
        return "'" + value
    return value


def get(path, params, tries=5):
    # 429 and 503 are retryable; the error body may say how long to wait.
    global calls
    for attempt in range(tries):
        r = requests.get(f"{BASE}/{path}", headers=HEADERS, params=params, timeout=90)
        calls += 1
        if r.status_code == 400:  # malformed handle or query: skip it, keep the rest of the run
            print("bad request:", r.json()["error"]["message"].splitlines()[0])
            return None
        if r.status_code not in (429, 503) or attempt == tries - 1:
            r.raise_for_status()
            return r.json().get("data")  # None when the account does not exist
        try:
            wait = r.json()["error"]["details"]["retryAfter"]
        except (ValueError, KeyError, TypeError):
            wait = 5 * (attempt + 1)
        time.sleep(min(wait, 60))


def posts(source, max_pages):
    # source is a handle ("NASA") or a search ("search:artemis"); follow the cursor page by page.
    if source.startswith("search:"):
        path, params = "search", {"query": source[7:].strip(), "sort": "latest"}
    else:
        path, params = "profile/posts", {"handle": source.lstrip("@")}
    for page in range(max_pages):
        data = get(path, params)
        if not data or not data["posts"]:
            if page == 0:
                print(f"skipped {source}: no record or no posts")
            return
        yield from data["posts"]
        if not data["has_more"]:
            return
        params["cursor"] = data["cursor"]


def row(source, p):
    return {
        "source": source, "post_id": p["id"], "handle": p["author"]["handle"],
        "posted": p["created_at"], "likes": p["like_count"], "replies": p["reply_count"],
        "reposts": p["repost_count"], "quotes": p["quote_count"], "views": p["view_count"],
        "bookmarks": p["bookmark_count"], "text": (p["text"] or "").replace("\n", " "),
        "url": p["url"],
    }


def main(sources, pages="3", out="x_posts.csv"):
    seen = set()
    with open(out, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        for source in [s.strip() for s in sources.split(",") if s.strip()]:
            for p in posts(source, int(pages)):
                if p["id"] not in seen:
                    seen.add(p["id"])
                    writer.writerow({k: cell(v) for k, v in row(source, p).items()})
    print(f"wrote {len(seen)} posts to {out} in {calls} calls")


if __name__ == "__main__":
    main(*sys.argv[1:])

An unknown handle returns HTTP 200 with {"data": null} on the profile endpoint and an empty list on the posts endpoint. The script skips both with a message. cell() puts an apostrophe in front of any text that starts with =, +, - or @, so a spreadsheet shows it as text instead of running it as a formula.

Run the script

bash
export TOOLZERHUB_API_KEY=your_key
python x_posts.py "NASA, github, nobody_here_qq9, search:artemis" 3 x_posts.csv

Output on 2026-10-16:

text
skipped nobody_here_qq9: no record or no posts
wrote 180 posts in 10 calls

It took 14 seconds. The three pages for each source gave 60 posts:

Source Posts Date range Median likes Median views
NASA 60 2026-09-23 to 2026-10-16 2,513 974,391
github 60 2026-09-17 to 2026-10-16 242 69,200
search:artemis 60 2026-10-16, 18 minutes 0 1

The search sorts by latest, so it returns posts minutes old with no engagement yet. For engagement use sort=top: from:github with sort=top returned 19 posts dated 2021-09-21 to 2026-10-16, older than the 7 days X's recent search covers. All 180 post ids were unique, so each page gave new posts.

Where X's API is the better pick

  • Posting, DMs and anything that writes. Our API reads public data only.
  • Your own account's bookmarks and blocks (X's Owned Reads are $0.001 per resource), and streaming.
  • Bigger pages. X returns up to 100 posts or 1,000 followers per request; we returned 20 and 200.
  • Enterprise access, compliance feeds and a contract with X.

What it costs

On our side, 1,000 posts are 50 calls at 5 credits, or 250 credits. We charge $0.99 to $1.90 per 1,000 credits: $0.99 on the $495 plan, $1.45 on the $29 plan, $1.90 on the smallest pack. The free tier is 100 credits a month, enough for 20 posts calls, about 400 posts.

Job X, pay-per-use ToolzerHub
1,000 posts $5.00 $0.25 to $0.48 (250 credits)
1,000 followers $10.00 $0.015 to $0.029 (15 credits)
1 profile $0.010 $0.001 to $0.002 (1 credit)
The 180-post run above $0.90 $0.05 to $0.10 (50 credits)

The run's cost is 10 calls at 5 credits, and it includes the skipped handle's call. X's column assumes every post is a first read that day. X charges a repeated resource once per UTC day, so a same-day re-run costs less than the table shows.

Reddit and Meta also limit or charge for their APIs: see what Reddit's API costs and Threads keyword search limits.

We are not affiliated with X Corp.

Sources

Get this data from your own code

The X (Twitter) API returns it as JSON with one x-api-key header. 100 free credits monthly.