# Twitter API Python Client with requests Canonical: https://www.twitterapis.com/sdk/python Description: A complete Python client for the TwitterAPIs X data API in about fifteen lines: session auth, query building, error handling and cursor pagination. Generated: 2026-09-17T01:57:10.003Z --- 1. [Home](/) 2. / [Language clients](/sdk) 3. / Python PYTHON # Twitter API Python client ## How do I call the Twitter API from Python? The Python client for TwitterAPIs is a requests session with one header on it. There is no package to install beyond requests itself, no OAuth flow, and no token to refresh, because the key is a static Bearer credential that goes on every call. Set it once on a session, write one helper that builds the URL and decodes the JSON, and you have covered every read endpoint the API serves. pip install requests twitterapis.py Copy ``` import os import requests BASE = "https://api.twitterapis.com" KEY = os.environ["TWITTERAPIS_KEY"] session = requests.Session() session.headers["Authorization"] = f"Bearer {KEY}" def get(path, **params): """Call any read endpoint. path is the docs path, e.g. 'user/info'.""" res = session.get(f"{BASE}/twitter/{path}", params=params, timeout=30) res.raise_for_status() return res.json() # Resolve a handle to the permanent numeric user ID profile = get("user/info", username="naval") print(profile["user"]["id"], profile["user"]["followers_count"]) # Search posts, then page with the returned cursor page = get("tweet/advanced_search", query="from:naval min_faves:500") for tweet in page["tweets"]: print(tweet["id"], tweet["text"][:80]) ``` ## Paginating a follower list Cursor-paginated endpoints return a next cursor alongside the page of results. Wrapping that in a generator keeps the cursor logic in one place, so the calling code is an ordinary loop that never has to know pagination exists. How many times that loop runs is the number worth knowing before you start it, because billing is per call rather than per record. Across 396,817 successful tweet-returning read calls on our own billing logs, 13 to 17 August 2026, a timeline read returned 18.78 records on average and a search read returned 7.62, with 29.5% of search calls returning nothing at all and still counting. Divide the records you need by the figure for the endpoint you are actually calling, not by the page size you asked for. Pagination Copy ``` def paginate(path, collection, max_calls=500, **params): """Yield each page's ROWS. Stops on an empty page, on a spent cursor, or at max_calls, whichever comes first. Both terminators are required. Search and list endpoints null the cursor on a page that is still FULL, so an empty-page check alone drops the last page. Follower-graph endpoints never null the cursor, so a cursor check alone never returns. params is never mutated: a stale cursor left in it re-fetches the same page forever.""" cursor, calls, seen = None, 0, set() while calls < max_calls: page = get(path, **({**params, "cursor": cursor} if cursor else params)) calls += 1 rows = page.get(collection) or [] if not rows: return yield rows cursor = page.get("next_cursor") if not cursor: return if cursor in seen: # catches a stuck cursor AND any cycle raise RuntimeError(f"cursor stopped advancing at {cursor}") seen.add(cursor) raise RuntimeError(f"hit the {max_calls}-call cap, resume from {cursor}") total = 0 for rows in paginate("user/followers", "users", username="naval"): total += len(rows) print(total) ``` ## Retries that do not cost you money Because billing is per call, a retry policy is a spending policy. Retry a server error, never retry a client error, and put a timeout on every request so a hung connection cannot stall a job silently. Retries Copy ``` from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # Retry 5xx with backoff. Never retry a 4xx: a 401 is a bad key and a 404 # is an account that does not exist, and repeating either just costs money. retry = Retry( total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504], allowed_methods=["GET"], ) session.mount("https://", HTTPAdapter(max_retries=retry)) try: profile = get("user/info", username="naval") except requests.HTTPError as exc: if exc.response.status_code == 401: raise SystemExit("Key rejected. Check TWITTERAPIS_KEY.") raise ``` ## Where to go next The same client shape in [Node](/sdk/node) and [Go](/sdk/go), or all six languages together on the [language clients](/sdk) page. For the endpoint you are about to call, the [search API](/twitter-search-api) and [followers API](/twitter-followers-api) pages cover parameters and response shapes, and [the Tweepy comparison](/twitterapis-vs-tweepy) covers what changes if you are moving off it. ## Frequently Asked Questions ### Do I need a Python SDK for the Twitter API? No. The client above is the whole thing: a requests session with one header set on it, plus a function that builds the URL and decodes the JSON. Because the header never changes and there is no token to refresh, attaching it to the session once means every subsequent call is authenticated without you thinking about it again. ### How do I paginate followers in Python? Read the cursor field from each response and pass it back as the cursor parameter on the next call, stopping when the response no longer carries one. The generator on this page does exactly that, so a caller writes an ordinary for loop and never touches cursor handling. Each page is one billed call, so wrap the loop in a page limit when you are testing. ### How do I keep the API key out of my source? Read it from the environment, as the client above does with os.environ. A key committed to a repository is a key you must rotate, and a key interpolated into a notebook cell tends to end up in the notebook output. For a scheduled job, put it in whatever secret store your runner already has rather than in the job definition. ### How does this compare to Tweepy? Tweepy is a wrapper around the official X API, so it inherits that API's pricing, its OAuth flow and its rate windows. It cannot be pointed at a different provider by swapping a base URL, because the endpoints and response shapes differ. Migrating usually means replacing the handful of Tweepy calls you actually use with the get function above, which is less work than the word migration suggests. ### Should I use async Python for this? Only if you are fetching many independent resources at once. For a sequential job, requests is simpler and the bottleneck is the network rather than the client. If you do need concurrency, httpx with an AsyncClient takes the same header and the same URLs, so the client function converts almost line for line. ### What does a call cost from Python? The same as from anywhere else: $0.0008 for a standard read call, billed per call with no plan minimum. New accounts start with $0.50 of credit, about 625 read calls, which is enough to page a real follower list before you commit to a budget. The client makes no hidden requests, so the number of calls you are billed for is the number of times your code calls get. Pagination is the case to watch, because one loop over a large follower list is one call per page. [Quickstart](/quickstart)[Start Free](/signup) [ TwitterAPIs ](/) The cheapest pay-as-you-go Twitter and X API. $0.0008 per call, which works out to $0.04 per 1,000 tweets on a full 20-tweet page. No subscriptions and no developer account. ## Product / API - [Pricing](/pricing) - [Cost Calculator](/twitter-api-cost-calculator) - [Rate Limits](/twitter-api-rate-limits) - [MCP Server](/mcp) - [Integrations](/integrations) - [Language Clients](/sdk) - [Changelog](/changelog) - [Status](/status) ## Developers - [Documentation](https://docs.twitterapis.com) - [API Reference](https://docs.twitterapis.com/docs/reference/search/tweet-advanced-search) - [User Info](https://docs.twitterapis.com/docs/reference/user-reads/user-info) - [User Tweets](https://docs.twitterapis.com/docs/reference/user-reads/user-tweets) - [Advanced Search](https://docs.twitterapis.com/docs/reference/search/tweet-advanced-search) - [Verified Followers](https://docs.twitterapis.com/docs/reference/follower-graph/user-verified-followers) ## Resources / Compare - [Answers](/answers) - [Reviews](/reviews) - [Free Tools](/tools) - [Twitter ID Finder](/tools/twitter-id-finder) - [Get a Twitter API Key](/twitter-api-key) - [Official X API Comparison](/twitter-api-pricing) - [Twitter API Use Cases](/twitter-api-usecases) - [Twitter API Alternatives](/twitter-api-alternatives) - [Twitter Unofficial API](/twitter-unofficial-api) - [Twitter Free API](/twitter-free-api) - [TwitterAPIs vs twitterapi.io](/twitterapis-vs-twitterapi-io) - [TwitterAPIs vs GetXAPI](/twitterapis-vs-getxapi) - [TwitterAPIs vs TweetAPI](/twitterapis-vs-tweetapi) - [TwitterAPIs vs TwexAPI](/twitterapis-vs-twexapi) - [TwitterAPIs vs RapidAPI](/twitterapis-vs-rapidapi) ## Legal - [About](/about) - [Security](/security) - [Trust](/privacy-and-data-handling) - [Terms of Service](/terms-of-service) - [Affiliates](/affiliates) - [Contact](/contact) - [Jobs](/jobs) © 2026 TwitterAPIs. All rights reserved. TwitterAPIs is an independent third-party API for developers and researchers. Not affiliated with, endorsed by, or sponsored by X Corp. All systems operational