TweetAPI Python SDK
Official Python SDK for TweetAPI — the Twitter/X Data API for developers and researchers.
Access tweets, user profiles, followers, analytics, and full interaction capabilities. 70+ endpoints with built-in error handling and type hints.
Install
pip install tweetapi
Quick Start
from tweetapi import TweetAPI
client = TweetAPI(api_key="YOUR_API_KEY")
# Get a user profile
user = client.user.get_by_username(username="elonmusk")
print(user["data"]["followerCount"]) # 180000000
# Search tweets
results = client.explore.search(query="bitcoin", type="Latest")
# Get followers with pagination
followers = client.user.get_followers(user_id="123456")
next_page = client.user.get_followers(
user_id="123456",
cursor=followers["pagination"]["nextCursor"],
)
Get your free API key — 100 requests, no credit card required
Features
- 70+ endpoints covering users, tweets, posts, interactions, DMs, communities, spaces, and search
- Full type hints with TypedDict response types for IDE autocomplete
- Automatic retry with backoff on rate limits (429) and server errors (5xx)
- Auto-pagination helpers — iterate all pages with a simple
forloop - Solid error handling with typed exceptions (
RateLimitError,NotFoundError, etc.) - Rate limit awareness —
retry_afterrespected automatically, state exposed viaclient.rate_limit_info - Split timeouts — separate connect and read timeouts
- Single dependency —
requestsonly - Python 3.9+ compatible
API Reference
User
| Method | Description |
|---|---|
client.user.get_by_username(username=...) |
Get user profile by username |
client.user.get_by_usernames(usernames=...) |
Get multiple users (comma-separated) |
client.user.get_by_user_id(user_id=...) |
Get user profile by ID |
client.user.get_by_user_ids(user_ids=...) |
Get multiple users by IDs |
client.user.get_tweets(user_id=...) |
Get a user's tweets |
client.user.get_tweets_and_replies(user_id=...) |
Get tweets and replies |
client.user.get_following(user_id=...) |
Get who a user follows |
client.user.get_followers(user_id=...) |
Get a user's followers |
client.user.get_verified_followers(user_id=...) |
Get verified followers |
client.user.get_subscriptions(user_id=...) |
Get subscriptions |
client.user.get_following_v1(user_id=...) |
Get following (v1, supports count) |
client.user.get_followers_v1(user_id=...) |
Get followers (v1, supports count) |
client.user.get_following_ids(user_id=...) |
Get following user IDs |
client.user.get_followers_ids(user_id=...) |
Get follower user IDs |
client.user.check_follow(subject_id=..., target_id=...) |
Check follow relationship |
client.user.about_account(username=...) |
Get account transparency info |
Tweet
| Method | Description |
|---|---|
client.tweet.get_details_and_conversation(tweet_id=...) |
Get tweet details and replies |
client.tweet.get_details_by_ids(ids=...) |
Get multiple tweets (max 200) |
client.tweet.get_retweets(tweet_id=...) |
Get who retweeted |
client.tweet.get_quotes(tweet_id=...) |
Get quote tweets |
client.tweet.translate(tweet_id=..., dst_lang=...) |
Translate a tweet |
Post
| Method | Description |
|---|---|
client.post.create_post(auth_token=..., text=..., proxy=..., reply_option=...) |
Create a tweet |
client.post.create_post_quote(auth_token=..., text=..., attachment_url=..., proxy=..., reply_option=...) |
Quote tweet |
client.post.create_post_with_media(auth_token=..., text=..., media=..., proxy=..., reply_option=...) |
Tweet with media |
client.post.reply_post(auth_token=..., text=..., tweet_id=..., proxy=...) |
Reply to a tweet |
client.post.reply_post_with_media(...) |
Reply with media |
client.post.delete_post(auth_token=..., tweet_id=...) |
Delete a tweet |
Profile
| Method | Description |
|---|---|
client.profile.update(auth_token=..., name=..., bio=..., location=..., website=..., proxy=...) |
Update profile fields |
client.profile.avatar(auth_token=..., media=..., proxy=...) |
Update profile avatar |
client.profile.banner(auth_token=..., media=..., proxy=...) |
Update profile banner |
client.profile.remove_banner(auth_token=..., proxy=...) |
Remove the profile banner |
client.profile.set_privacy(auth_token=..., is_private=..., proxy=...) |
Make the account public or private |
Interaction
| Method | Description |
|---|---|
client.interaction.favorite_post(auth_token=..., tweet_id=...) |
Like a tweet |
client.interaction.unfavorite_post(auth_token=..., tweet_id=...) |
Unlike a tweet |
client.interaction.retweet(auth_token=..., tweet_id=...) |
Retweet |
client.interaction.delete_retweet(auth_token=..., tweet_id=...) |
Remove retweet |
client.interaction.bookmark(auth_token=..., tweet_id=...) |
Bookmark a tweet |
client.interaction.delete_bookmark(auth_token=..., tweet_id=...) |
Remove bookmark |
client.interaction.follow(auth_token=..., user_id=...) |
Follow a user |
client.interaction.unfollow(auth_token=..., user_id=...) |
Unfollow a user |
client.interaction.add_member_to_list(auth_token=..., list_id=..., user_id=...) |
Add to list |
client.interaction.remove_member_from_list(auth_token=..., list_id=..., user_id=...) |
Remove from list |
client.interaction.get_notifications(auth_token=...) |
Get notifications |
client.interaction.get_user_analytics(auth_token=...) |
Get analytics |
List
| Method | Description |
|---|---|
client.list.get_details(list_id=...) |
Get list details |
client.list.get_tweets(list_id=...) |
Get tweets in a list |
client.list.get_members(list_id=...) |
Get list members |
client.list.get_followers(list_id=...) |
Get list followers |
client.list.create(auth_token=..., name=..., description=..., is_private=...) |
Create a list |
client.list.add_member(auth_token=..., list_id=..., user_id=..., proxy=...) |
Add a member |
client.list.remove_member(auth_token=..., list_id=..., user_id=..., proxy=...) |
Remove a member |
Community
| Method | Description |
|---|---|
client.community.get_details(community_id=...) |
Get community details |
client.community.get_tweets(community_id=..., sort_by=...) |
Get community tweets |
client.community.get_members(community_id=...) |
Get members |
client.community.search(query=...) |
Search communities |
client.community.create_post(auth_token=..., text=..., community_id=..., proxy=...) |
Post in community |
client.community.create_post_with_media(...) |
Post with media |
client.community.create_quote(auth_token=..., text=..., attachment_url=..., community_id=..., proxy=...) |
Quote post in community |
client.community.create_quote_with_media(...) |
Quote post with media |
client.community.reply_post(...) |
Reply to community post |
client.community.reply_post_with_media(...) |
Reply with media |
client.community.join(auth_token=..., community_id=...) |
Join |
client.community.leave(auth_token=..., community_id=...) |
Leave |
Space
| Method | Description |
|---|---|
client.space.get_by_id(space_id=...) |
Get Space details |
client.space.get_stream_url(media_key=...) |
Get HLS stream URL |
Explore
| Method | Description |
|---|---|
client.explore.search(query=..., type=...) |
Search tweets/users/photos/videos |
Auth
| Method | Description |
|---|---|
client.auth.login(username=..., password=..., proxy=..., country=...) |
Log in, get auth tokens |
country is the ISO 3166-1 alpha-2 code for the proxy's public egress IP (for example, "US"). It must match the IP used for the complete login attempt. Pass two_factor_secret when the account uses TOTP-based 2FA.
X Chat (Encrypted DMs)
| Method | Description |
|---|---|
client.xchat.setup(auth_token=..., user_id=..., pin=...) |
Initialize encrypted DMs |
client.xchat.get_conversations(auth_token=...) |
List conversations |
client.xchat.send(auth_token=..., recipient_id=..., message=...) |
Send message |
client.xchat.get_history(auth_token=..., conversation_id=...) |
Get history |
client.xchat.can_dm(auth_token=..., user_ids=...) |
Check DM availability |
Unencrypted DMs
| Method | Description |
|---|---|
client.dm.send_dm(auth_token=..., conversation_id=..., text=..., proxy=...) |
Send DM |
client.dm.get_dm_permissions(auth_token=..., recipient_ids=...) |
Check permissions |
client.dm.get_inbox_initial_state(auth_token=...) |
Get inbox state |
client.dm.get_inbox_trusted(auth_token=..., cursor=...) |
Trusted inbox |
client.dm.get_inbox_untrusted(auth_token=..., cursor=...) |
Message requests |
client.dm.get_conversation(auth_token=..., conversation_id=...) |
Get messages |
client.dm.get_dm_user_updates(auth_token=..., cursor=...) |
DM user updates |
client.dm.accept_conversation(auth_token=..., conversation_id=...) |
Accept request |
Posting and Profile Media
Tweet media accepts an existing TweetAPI media ID, a URL, or inline base64 data:
client.post.create_post_with_media(
auth_token="AUTH_TOKEN",
text="Launch update",
media=[{"media_id": "1971008286821380096"}],
proxy="host:port:user:pass",
)
Use reply_option to set reply controls when creating standard, quote, or media posts:
client.post.create_post(
auth_token="AUTH_TOKEN",
text="Followers can reply",
proxy="host:port:user:pass",
reply_option={"mode": "followers"},
)
Profile avatar and banner uploads accept a URL or inline data plus type:
client.profile.update(auth_token="AUTH_TOKEN", name="New Name", bio="Builder")
client.profile.avatar(
auth_token="AUTH_TOKEN",
media={"url": "https://example.com/avatar.jpg"},
)
client.profile.banner(
auth_token="AUTH_TOKEN",
media={"data": "BASE64_IMAGE_DATA", "type": "image/png"},
)
client.profile.remove_banner(auth_token="AUTH_TOKEN")
client.profile.set_privacy(auth_token="AUTH_TOKEN", is_private=True)
Canonical list mutations live under client.list; the legacy interaction list helpers remain available:
created = client.list.create(
auth_token="AUTH_TOKEN",
name="Research",
description="Accounts to watch",
is_private=True,
)
client.list.add_member(auth_token="AUTH_TOKEN", list_id=created["data"]["id"], user_id="123")
client.list.remove_member(auth_token="AUTH_TOKEN", list_id=created["data"]["id"], user_id="123")
Community quote posts support the same URL and media attachment shapes:
client.community.create_quote(
auth_token="AUTH_TOKEN",
text="Useful context",
attachment_url="https://x.com/user/status/123",
community_id="987",
proxy="host:port:user:pass",
)
client.community.create_quote_with_media(
auth_token="AUTH_TOKEN",
text="Useful context",
attachment_url="https://x.com/user/status/123",
community_id="987",
media=[{"media_id": "1971008286821380096"}],
proxy="host:port:user:pass",
)
Auto-Pagination
Use the paginate() and paginate_pages() helpers to iterate through all pages automatically:
from tweetapi import TweetAPI, paginate, paginate_pages
client = TweetAPI(api_key="YOUR_API_KEY")
# Iterate individual items across all pages
for user in paginate(
lambda cursor: client.user.get_followers(user_id="123456", cursor=cursor),
):
print(user["username"])
# Iterate full pages (access page-level data)
for page in paginate_pages(
lambda cursor: client.explore.search(query="bitcoin", type="Latest", cursor=cursor),
max_pages=5, # optional: limit number of pages
):
print(f"Got {len(page['data'])} results")
print(f"Next cursor: {page['pagination']['nextCursor']}")
Works with any paginated endpoint — followers, tweets, search results, list members, community posts, etc.
Automatic Retry with Backoff
The SDK automatically retries on transient errors with exponential backoff:
- 429 (Rate Limit) — waits the
retry_afterduration from the API, then retries - 5xx (Server Error) — retries with exponential backoff + jitter
- Network errors — retries on timeouts and connection failures
- 4xx (Client Error) — never retried (400, 401, 403, 404 fail immediately)
Default: 3 retries, 2x backoff, 1s initial delay, 30s max delay.
# Customize retry behavior
client = TweetAPI(
api_key="YOUR_API_KEY",
max_retries=5, # default: 3
initial_retry_delay=2.0, # default: 1.0 (seconds)
backoff_multiplier=3.0, # default: 2.0
max_retry_delay=60.0, # default: 30.0 (seconds)
)
# Disable retries entirely
client = TweetAPI(api_key="YOUR_API_KEY", max_retries=0)
Rate Limit Awareness
After a 429 response, the SDK exposes the last known rate limit state:
print(client.rate_limit_info)
# {"retry_after": 30, "timestamp": 1712345678.0} — or None if no 429 encountered
Error Handling
The SDK raises typed exceptions you can catch and handle. With automatic retries enabled (default), you'll only see these after all retry attempts are exhausted:
from tweetapi import (
TweetAPI,
TweetAPIError,
AuthenticationError,
RateLimitError,
NotFoundError,
ValidationError,
ServerError,
NetworkError,
)
client = TweetAPI(api_key="YOUR_API_KEY")
try:
user = client.user.get_by_username(username="elonmusk")
except RateLimitError as e:
print(f"Rate limited. Retry in {e.retry_after}s")
except NotFoundError:
print("User not found")
except AuthenticationError:
print("Invalid API key")
except ValidationError as e:
print(f"Bad request: {e.message}")
except ServerError:
print("API is having issues, try again later")
except NetworkError:
print("Network error — check your connection")
except TweetAPIError as e:
print(f"Error [{e.code}]: {e.message}")
Every error includes:
code— API error code (e.g.,"ACCOUNT_SUSPENDED","RATE_LIMIT")status_code— HTTP status codemessage— Human-readable error messagedetails— Additional context (field, reason, retry_after, etc.)
Configuration
client = TweetAPI(
api_key="YOUR_API_KEY", # Required
base_url="https://...", # Optional (default: https://api.tweetapi.com)
timeout=30, # Optional — single value for both connect + read
connect_timeout=10.0, # Optional (default: 10s)
read_timeout=30.0, # Optional (default: 30s)
max_retries=3, # Optional (default: 3, set 0 to disable)
backoff_multiplier=2.0, # Optional (default: 2.0)
initial_retry_delay=1.0, # Optional (default: 1.0s)
max_retry_delay=30.0, # Optional (default: 30.0s)
)
# You can also pass a tuple for timeout
client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
Requirements
- Python 3.9+
requestslibrary
Links
License
MIT
TweetAPI is a third-party service and is not affiliated with X Corp.
Metadata
Release files for tweetapi 2.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tweetapi-2.2.0.tar.gz | 16.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tweetapi-2.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.0 kB
Release files / tweetapi-2.2.0.tar.gz
| Download URL | tweetapi-2.2.0.tar.gz |
|---|---|
| Size | 16.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ceb075e3841f1cc8421a56ad98e850d503b7b3e67d3fc023af089d01695d8668
|
|
BLAKE2b-256 checksum How to use checksums |
9aa4cf06a05eeed16f6caf650180af31a415b38d3adc258c3e9673dd0ff4fac0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.13
|
Release files / tweetapi-2.2.0-py3-none-any.whl
| Download URL | tweetapi-2.2.0-py3-none-any.whl |
|---|---|
| Size | 23.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d104b2a9aa1f1ff4689d80d7a95bf78606f750b1c648297bb4d2d68454b6c740
|
|
BLAKE2b-256 checksum How to use checksums |
1063ac1045b659b223f3440ee31b87bf846d263cde7ff4cf493612198daaf246
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.13
|