tweetapi 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ {
2
+ "includeCoAuthoredBy": false
3
+ }
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ *.egg
8
+ .venv/
9
+ venv/
10
+ .env
11
+ .env.*
12
+ .pytest_cache/
@@ -0,0 +1,345 @@
1
+ Metadata-Version: 2.4
2
+ Name: tweetapi
3
+ Version: 1.1.0
4
+ Summary: Official Python SDK for TweetAPI — Twitter/X Data API for developers and researchers
5
+ Project-URL: Homepage, https://tweetapi.com?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
6
+ Project-URL: Documentation, https://tweetapi.com/docs?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
7
+ Project-URL: Repository, https://github.com/tweetapi/python
8
+ Project-URL: Issues, https://github.com/tweetapi/python/issues
9
+ Author-email: TweetAPI <support@tweetapi.com>
10
+ License-Expression: MIT
11
+ Keywords: social media api,tweet api,tweetapi,tweets,twitter,twitter api,twitter client,twitter data,twitter library,twitter sdk,twitter wrapper,x api
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet :: WWW/HTTP
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: requests>=2.28.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Requires-Dist: responses>=0.23.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # TweetAPI Python SDK
32
+
33
+ Official Python SDK for [TweetAPI](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk) — the Twitter/X Data API for developers and researchers.
34
+
35
+ Access tweets, user profiles, followers, analytics, and full interaction capabilities. 70+ endpoints with built-in error handling and type hints.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install tweetapi
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ from tweetapi import TweetAPI
47
+
48
+ client = TweetAPI(api_key="YOUR_API_KEY")
49
+
50
+ # Get a user profile
51
+ user = client.user.get_by_username(username="elonmusk")
52
+ print(user["data"]["followerCount"]) # 180000000
53
+
54
+ # Search tweets
55
+ results = client.explore.search(query="bitcoin", type="Latest")
56
+
57
+ # Get followers with pagination
58
+ followers = client.user.get_followers(user_id="123456")
59
+ next_page = client.user.get_followers(
60
+ user_id="123456",
61
+ cursor=followers["pagination"]["nextCursor"],
62
+ )
63
+ ```
64
+
65
+ > **Get your free API key** — [100 requests, no credit card required](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
66
+
67
+ ## Features
68
+
69
+ - **70+ endpoints** covering users, tweets, posts, interactions, DMs, communities, spaces, and search
70
+ - **Full type hints** with TypedDict response types for IDE autocomplete
71
+ - **Automatic retry with backoff** on rate limits (429) and server errors (5xx)
72
+ - **Auto-pagination helpers** — iterate all pages with a simple `for` loop
73
+ - **Solid error handling** with typed exceptions (`RateLimitError`, `NotFoundError`, etc.)
74
+ - **Rate limit awareness** — `retry_after` respected automatically, state exposed via `client.rate_limit_info`
75
+ - **Split timeouts** — separate connect and read timeouts
76
+ - **Single dependency** — `requests` only
77
+ - **Python 3.9+** compatible
78
+
79
+ ## API Reference
80
+
81
+ ### User
82
+
83
+ | Method | Description |
84
+ |--------|-------------|
85
+ | `client.user.get_by_username(username=...)` | Get user profile by username |
86
+ | `client.user.get_by_usernames(usernames=...)` | Get multiple users (comma-separated) |
87
+ | `client.user.get_by_user_id(user_id=...)` | Get user profile by ID |
88
+ | `client.user.get_by_user_ids(user_ids=...)` | Get multiple users by IDs |
89
+ | `client.user.get_tweets(user_id=...)` | Get a user's tweets |
90
+ | `client.user.get_tweets_and_replies(user_id=...)` | Get tweets and replies |
91
+ | `client.user.get_following(user_id=...)` | Get who a user follows |
92
+ | `client.user.get_followers(user_id=...)` | Get a user's followers |
93
+ | `client.user.get_verified_followers(user_id=...)` | Get verified followers |
94
+ | `client.user.get_subscriptions(user_id=...)` | Get subscriptions |
95
+ | `client.user.get_following_v1(user_id=...)` | Get following (v1, supports count) |
96
+ | `client.user.get_followers_v1(user_id=...)` | Get followers (v1, supports count) |
97
+ | `client.user.get_following_ids(user_id=...)` | Get following user IDs |
98
+ | `client.user.get_followers_ids(user_id=...)` | Get follower user IDs |
99
+ | `client.user.check_follow(subject_id=..., target_id=...)` | Check follow relationship |
100
+ | `client.user.about_account(username=...)` | Get account transparency info |
101
+
102
+ ### Tweet
103
+
104
+ | Method | Description |
105
+ |--------|-------------|
106
+ | `client.tweet.get_details_and_conversation(tweet_id=...)` | Get tweet details and replies |
107
+ | `client.tweet.get_details_by_ids(ids=...)` | Get multiple tweets (max 200) |
108
+ | `client.tweet.get_retweets(tweet_id=...)` | Get who retweeted |
109
+ | `client.tweet.get_quotes(tweet_id=...)` | Get quote tweets |
110
+ | `client.tweet.translate(tweet_id=..., dst_lang=...)` | Translate a tweet |
111
+
112
+ ### Post
113
+
114
+ | Method | Description |
115
+ |--------|-------------|
116
+ | `client.post.create_post(auth_token=..., text=..., proxy=...)` | Create a tweet |
117
+ | `client.post.create_post_quote(auth_token=..., text=..., attachment_url=..., proxy=...)` | Quote tweet |
118
+ | `client.post.create_post_with_media(auth_token=..., text=..., media=..., proxy=...)` | Tweet with media |
119
+ | `client.post.reply_post(auth_token=..., text=..., tweet_id=..., proxy=...)` | Reply to a tweet |
120
+ | `client.post.reply_post_with_media(...)` | Reply with media |
121
+ | `client.post.delete_post(auth_token=..., tweet_id=...)` | Delete a tweet |
122
+
123
+ ### Interaction
124
+
125
+ | Method | Description |
126
+ |--------|-------------|
127
+ | `client.interaction.favorite_post(auth_token=..., tweet_id=...)` | Like a tweet |
128
+ | `client.interaction.unfavorite_post(auth_token=..., tweet_id=...)` | Unlike a tweet |
129
+ | `client.interaction.retweet(auth_token=..., tweet_id=...)` | Retweet |
130
+ | `client.interaction.delete_retweet(auth_token=..., tweet_id=...)` | Remove retweet |
131
+ | `client.interaction.bookmark(auth_token=..., tweet_id=...)` | Bookmark a tweet |
132
+ | `client.interaction.delete_bookmark(auth_token=..., tweet_id=...)` | Remove bookmark |
133
+ | `client.interaction.follow(auth_token=..., user_id=...)` | Follow a user |
134
+ | `client.interaction.unfollow(auth_token=..., user_id=...)` | Unfollow a user |
135
+ | `client.interaction.add_member_to_list(auth_token=..., list_id=..., user_id=...)` | Add to list |
136
+ | `client.interaction.remove_member_from_list(auth_token=..., list_id=..., user_id=...)` | Remove from list |
137
+ | `client.interaction.get_notifications(auth_token=...)` | Get notifications |
138
+ | `client.interaction.get_user_analytics(auth_token=...)` | Get analytics |
139
+
140
+ ### List
141
+
142
+ | Method | Description |
143
+ |--------|-------------|
144
+ | `client.list.get_details(list_id=...)` | Get list details |
145
+ | `client.list.get_tweets(list_id=...)` | Get tweets in a list |
146
+ | `client.list.get_members(list_id=...)` | Get list members |
147
+ | `client.list.get_followers(list_id=...)` | Get list followers |
148
+
149
+ ### Community
150
+
151
+ | Method | Description |
152
+ |--------|-------------|
153
+ | `client.community.get_details(community_id=...)` | Get community details |
154
+ | `client.community.get_tweets(community_id=..., sort_by=...)` | Get community tweets |
155
+ | `client.community.get_members(community_id=...)` | Get members |
156
+ | `client.community.search(query=...)` | Search communities |
157
+ | `client.community.create_post(auth_token=..., text=..., community_id=..., proxy=...)` | Post in community |
158
+ | `client.community.create_post_with_media(...)` | Post with media |
159
+ | `client.community.reply_post(...)` | Reply to community post |
160
+ | `client.community.reply_post_with_media(...)` | Reply with media |
161
+ | `client.community.join(auth_token=..., community_id=...)` | Join |
162
+ | `client.community.leave(auth_token=..., community_id=...)` | Leave |
163
+
164
+ ### Space
165
+
166
+ | Method | Description |
167
+ |--------|-------------|
168
+ | `client.space.get_by_id(space_id=...)` | Get Space details |
169
+ | `client.space.get_stream_url(media_key=...)` | Get HLS stream URL |
170
+
171
+ ### Explore
172
+
173
+ | Method | Description |
174
+ |--------|-------------|
175
+ | `client.explore.search(query=..., type=...)` | Search tweets/users/photos/videos |
176
+
177
+ ### Auth
178
+
179
+ | Method | Description |
180
+ |--------|-------------|
181
+ | `client.auth.login(username=..., password=..., proxy=...)` | Log in, get auth tokens |
182
+
183
+ ### X Chat (Encrypted DMs)
184
+
185
+ | Method | Description |
186
+ |--------|-------------|
187
+ | `client.xchat.setup(auth_token=..., user_id=..., pin=...)` | Initialize encrypted DMs |
188
+ | `client.xchat.get_conversations(auth_token=...)` | List conversations |
189
+ | `client.xchat.send(auth_token=..., recipient_id=..., message=...)` | Send message |
190
+ | `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get history |
191
+ | `client.xchat.can_dm(auth_token=..., user_ids=...)` | Check DM availability |
192
+
193
+ ### Unencrypted DMs
194
+
195
+ | Method | Description |
196
+ |--------|-------------|
197
+ | `client.dm.send_dm(auth_token=..., conversation_id=..., text=..., proxy=...)` | Send DM |
198
+ | `client.dm.get_dm_permissions(auth_token=..., recipient_ids=...)` | Check permissions |
199
+ | `client.dm.get_inbox_initial_state(auth_token=...)` | Get inbox state |
200
+ | `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` | Trusted inbox |
201
+ | `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` | Message requests |
202
+ | `client.dm.get_conversation(auth_token=..., conversation_id=...)` | Get messages |
203
+ | `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | DM user updates |
204
+ | `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept request |
205
+
206
+ ## Auto-Pagination
207
+
208
+ Use the `paginate()` and `paginate_pages()` helpers to iterate through all pages automatically:
209
+
210
+ ```python
211
+ from tweetapi import TweetAPI, paginate, paginate_pages
212
+
213
+ client = TweetAPI(api_key="YOUR_API_KEY")
214
+
215
+ # Iterate individual items across all pages
216
+ for user in paginate(
217
+ lambda cursor: client.user.get_followers(user_id="123456", cursor=cursor),
218
+ ):
219
+ print(user["username"])
220
+
221
+ # Iterate full pages (access page-level data)
222
+ for page in paginate_pages(
223
+ lambda cursor: client.explore.search(query="bitcoin", type="Latest", cursor=cursor),
224
+ max_pages=5, # optional: limit number of pages
225
+ ):
226
+ print(f"Got {len(page['data'])} results")
227
+ print(f"Next cursor: {page['pagination']['nextCursor']}")
228
+ ```
229
+
230
+ Works with any paginated endpoint — followers, tweets, search results, list members, community posts, etc.
231
+
232
+ ## Automatic Retry with Backoff
233
+
234
+ The SDK automatically retries on transient errors with exponential backoff:
235
+
236
+ - **429 (Rate Limit)** — waits the `retry_after` duration from the API, then retries
237
+ - **5xx (Server Error)** — retries with exponential backoff + jitter
238
+ - **Network errors** — retries on timeouts and connection failures
239
+ - **4xx (Client Error)** — never retried (400, 401, 403, 404 fail immediately)
240
+
241
+ Default: 3 retries, 2x backoff, 1s initial delay, 30s max delay.
242
+
243
+ ```python
244
+ # Customize retry behavior
245
+ client = TweetAPI(
246
+ api_key="YOUR_API_KEY",
247
+ max_retries=5, # default: 3
248
+ initial_retry_delay=2.0, # default: 1.0 (seconds)
249
+ backoff_multiplier=3.0, # default: 2.0
250
+ max_retry_delay=60.0, # default: 30.0 (seconds)
251
+ )
252
+
253
+ # Disable retries entirely
254
+ client = TweetAPI(api_key="YOUR_API_KEY", max_retries=0)
255
+ ```
256
+
257
+ ### Rate Limit Awareness
258
+
259
+ After a 429 response, the SDK exposes the last known rate limit state:
260
+
261
+ ```python
262
+ print(client.rate_limit_info)
263
+ # {"retry_after": 30, "timestamp": 1712345678.0} — or None if no 429 encountered
264
+ ```
265
+
266
+ ## Error Handling
267
+
268
+ 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:
269
+
270
+ ```python
271
+ from tweetapi import (
272
+ TweetAPI,
273
+ TweetAPIError,
274
+ AuthenticationError,
275
+ RateLimitError,
276
+ NotFoundError,
277
+ ValidationError,
278
+ ServerError,
279
+ NetworkError,
280
+ )
281
+
282
+ client = TweetAPI(api_key="YOUR_API_KEY")
283
+
284
+ try:
285
+ user = client.user.get_by_username(username="elonmusk")
286
+ except RateLimitError as e:
287
+ print(f"Rate limited. Retry in {e.retry_after}s")
288
+ except NotFoundError:
289
+ print("User not found")
290
+ except AuthenticationError:
291
+ print("Invalid API key")
292
+ except ValidationError as e:
293
+ print(f"Bad request: {e.message}")
294
+ except ServerError:
295
+ print("API is having issues, try again later")
296
+ except NetworkError:
297
+ print("Network error — check your connection")
298
+ except TweetAPIError as e:
299
+ print(f"Error [{e.code}]: {e.message}")
300
+ ```
301
+
302
+ Every error includes:
303
+ - `code` — API error code (e.g., `"ACCOUNT_SUSPENDED"`, `"RATE_LIMIT"`)
304
+ - `status_code` — HTTP status code
305
+ - `message` — Human-readable error message
306
+ - `details` — Additional context (field, reason, retry_after, etc.)
307
+
308
+ ## Configuration
309
+
310
+ ```python
311
+ client = TweetAPI(
312
+ api_key="YOUR_API_KEY", # Required
313
+ base_url="https://...", # Optional (default: https://api.tweetapi.com)
314
+ timeout=30, # Optional — single value for both connect + read
315
+ connect_timeout=10.0, # Optional (default: 10s)
316
+ read_timeout=30.0, # Optional (default: 30s)
317
+ max_retries=3, # Optional (default: 3, set 0 to disable)
318
+ backoff_multiplier=2.0, # Optional (default: 2.0)
319
+ initial_retry_delay=1.0, # Optional (default: 1.0s)
320
+ max_retry_delay=30.0, # Optional (default: 30.0s)
321
+ )
322
+
323
+ # You can also pass a tuple for timeout
324
+ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
325
+ ```
326
+
327
+ ## Requirements
328
+
329
+ - Python 3.9+
330
+ - `requests` library
331
+
332
+ ## Links
333
+
334
+ - [Full Documentation](https://tweetapi.com/docs?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
335
+ - [Get API Key (Free)](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
336
+ - [Dashboard](https://tweetapi.com/dashboard?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
337
+ - [Node.js SDK](https://github.com/tweetapi/node)
338
+
339
+ ## License
340
+
341
+ MIT
342
+
343
+ ---
344
+
345
+ *TweetAPI is a third-party service and is not affiliated with X Corp.*
@@ -0,0 +1,315 @@
1
+ # TweetAPI Python SDK
2
+
3
+ Official Python SDK for [TweetAPI](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk) — the Twitter/X Data API for developers and researchers.
4
+
5
+ Access tweets, user profiles, followers, analytics, and full interaction capabilities. 70+ endpoints with built-in error handling and type hints.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install tweetapi
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from tweetapi import TweetAPI
17
+
18
+ client = TweetAPI(api_key="YOUR_API_KEY")
19
+
20
+ # Get a user profile
21
+ user = client.user.get_by_username(username="elonmusk")
22
+ print(user["data"]["followerCount"]) # 180000000
23
+
24
+ # Search tweets
25
+ results = client.explore.search(query="bitcoin", type="Latest")
26
+
27
+ # Get followers with pagination
28
+ followers = client.user.get_followers(user_id="123456")
29
+ next_page = client.user.get_followers(
30
+ user_id="123456",
31
+ cursor=followers["pagination"]["nextCursor"],
32
+ )
33
+ ```
34
+
35
+ > **Get your free API key** — [100 requests, no credit card required](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
36
+
37
+ ## Features
38
+
39
+ - **70+ endpoints** covering users, tweets, posts, interactions, DMs, communities, spaces, and search
40
+ - **Full type hints** with TypedDict response types for IDE autocomplete
41
+ - **Automatic retry with backoff** on rate limits (429) and server errors (5xx)
42
+ - **Auto-pagination helpers** — iterate all pages with a simple `for` loop
43
+ - **Solid error handling** with typed exceptions (`RateLimitError`, `NotFoundError`, etc.)
44
+ - **Rate limit awareness** — `retry_after` respected automatically, state exposed via `client.rate_limit_info`
45
+ - **Split timeouts** — separate connect and read timeouts
46
+ - **Single dependency** — `requests` only
47
+ - **Python 3.9+** compatible
48
+
49
+ ## API Reference
50
+
51
+ ### User
52
+
53
+ | Method | Description |
54
+ |--------|-------------|
55
+ | `client.user.get_by_username(username=...)` | Get user profile by username |
56
+ | `client.user.get_by_usernames(usernames=...)` | Get multiple users (comma-separated) |
57
+ | `client.user.get_by_user_id(user_id=...)` | Get user profile by ID |
58
+ | `client.user.get_by_user_ids(user_ids=...)` | Get multiple users by IDs |
59
+ | `client.user.get_tweets(user_id=...)` | Get a user's tweets |
60
+ | `client.user.get_tweets_and_replies(user_id=...)` | Get tweets and replies |
61
+ | `client.user.get_following(user_id=...)` | Get who a user follows |
62
+ | `client.user.get_followers(user_id=...)` | Get a user's followers |
63
+ | `client.user.get_verified_followers(user_id=...)` | Get verified followers |
64
+ | `client.user.get_subscriptions(user_id=...)` | Get subscriptions |
65
+ | `client.user.get_following_v1(user_id=...)` | Get following (v1, supports count) |
66
+ | `client.user.get_followers_v1(user_id=...)` | Get followers (v1, supports count) |
67
+ | `client.user.get_following_ids(user_id=...)` | Get following user IDs |
68
+ | `client.user.get_followers_ids(user_id=...)` | Get follower user IDs |
69
+ | `client.user.check_follow(subject_id=..., target_id=...)` | Check follow relationship |
70
+ | `client.user.about_account(username=...)` | Get account transparency info |
71
+
72
+ ### Tweet
73
+
74
+ | Method | Description |
75
+ |--------|-------------|
76
+ | `client.tweet.get_details_and_conversation(tweet_id=...)` | Get tweet details and replies |
77
+ | `client.tweet.get_details_by_ids(ids=...)` | Get multiple tweets (max 200) |
78
+ | `client.tweet.get_retweets(tweet_id=...)` | Get who retweeted |
79
+ | `client.tweet.get_quotes(tweet_id=...)` | Get quote tweets |
80
+ | `client.tweet.translate(tweet_id=..., dst_lang=...)` | Translate a tweet |
81
+
82
+ ### Post
83
+
84
+ | Method | Description |
85
+ |--------|-------------|
86
+ | `client.post.create_post(auth_token=..., text=..., proxy=...)` | Create a tweet |
87
+ | `client.post.create_post_quote(auth_token=..., text=..., attachment_url=..., proxy=...)` | Quote tweet |
88
+ | `client.post.create_post_with_media(auth_token=..., text=..., media=..., proxy=...)` | Tweet with media |
89
+ | `client.post.reply_post(auth_token=..., text=..., tweet_id=..., proxy=...)` | Reply to a tweet |
90
+ | `client.post.reply_post_with_media(...)` | Reply with media |
91
+ | `client.post.delete_post(auth_token=..., tweet_id=...)` | Delete a tweet |
92
+
93
+ ### Interaction
94
+
95
+ | Method | Description |
96
+ |--------|-------------|
97
+ | `client.interaction.favorite_post(auth_token=..., tweet_id=...)` | Like a tweet |
98
+ | `client.interaction.unfavorite_post(auth_token=..., tweet_id=...)` | Unlike a tweet |
99
+ | `client.interaction.retweet(auth_token=..., tweet_id=...)` | Retweet |
100
+ | `client.interaction.delete_retweet(auth_token=..., tweet_id=...)` | Remove retweet |
101
+ | `client.interaction.bookmark(auth_token=..., tweet_id=...)` | Bookmark a tweet |
102
+ | `client.interaction.delete_bookmark(auth_token=..., tweet_id=...)` | Remove bookmark |
103
+ | `client.interaction.follow(auth_token=..., user_id=...)` | Follow a user |
104
+ | `client.interaction.unfollow(auth_token=..., user_id=...)` | Unfollow a user |
105
+ | `client.interaction.add_member_to_list(auth_token=..., list_id=..., user_id=...)` | Add to list |
106
+ | `client.interaction.remove_member_from_list(auth_token=..., list_id=..., user_id=...)` | Remove from list |
107
+ | `client.interaction.get_notifications(auth_token=...)` | Get notifications |
108
+ | `client.interaction.get_user_analytics(auth_token=...)` | Get analytics |
109
+
110
+ ### List
111
+
112
+ | Method | Description |
113
+ |--------|-------------|
114
+ | `client.list.get_details(list_id=...)` | Get list details |
115
+ | `client.list.get_tweets(list_id=...)` | Get tweets in a list |
116
+ | `client.list.get_members(list_id=...)` | Get list members |
117
+ | `client.list.get_followers(list_id=...)` | Get list followers |
118
+
119
+ ### Community
120
+
121
+ | Method | Description |
122
+ |--------|-------------|
123
+ | `client.community.get_details(community_id=...)` | Get community details |
124
+ | `client.community.get_tweets(community_id=..., sort_by=...)` | Get community tweets |
125
+ | `client.community.get_members(community_id=...)` | Get members |
126
+ | `client.community.search(query=...)` | Search communities |
127
+ | `client.community.create_post(auth_token=..., text=..., community_id=..., proxy=...)` | Post in community |
128
+ | `client.community.create_post_with_media(...)` | Post with media |
129
+ | `client.community.reply_post(...)` | Reply to community post |
130
+ | `client.community.reply_post_with_media(...)` | Reply with media |
131
+ | `client.community.join(auth_token=..., community_id=...)` | Join |
132
+ | `client.community.leave(auth_token=..., community_id=...)` | Leave |
133
+
134
+ ### Space
135
+
136
+ | Method | Description |
137
+ |--------|-------------|
138
+ | `client.space.get_by_id(space_id=...)` | Get Space details |
139
+ | `client.space.get_stream_url(media_key=...)` | Get HLS stream URL |
140
+
141
+ ### Explore
142
+
143
+ | Method | Description |
144
+ |--------|-------------|
145
+ | `client.explore.search(query=..., type=...)` | Search tweets/users/photos/videos |
146
+
147
+ ### Auth
148
+
149
+ | Method | Description |
150
+ |--------|-------------|
151
+ | `client.auth.login(username=..., password=..., proxy=...)` | Log in, get auth tokens |
152
+
153
+ ### X Chat (Encrypted DMs)
154
+
155
+ | Method | Description |
156
+ |--------|-------------|
157
+ | `client.xchat.setup(auth_token=..., user_id=..., pin=...)` | Initialize encrypted DMs |
158
+ | `client.xchat.get_conversations(auth_token=...)` | List conversations |
159
+ | `client.xchat.send(auth_token=..., recipient_id=..., message=...)` | Send message |
160
+ | `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get history |
161
+ | `client.xchat.can_dm(auth_token=..., user_ids=...)` | Check DM availability |
162
+
163
+ ### Unencrypted DMs
164
+
165
+ | Method | Description |
166
+ |--------|-------------|
167
+ | `client.dm.send_dm(auth_token=..., conversation_id=..., text=..., proxy=...)` | Send DM |
168
+ | `client.dm.get_dm_permissions(auth_token=..., recipient_ids=...)` | Check permissions |
169
+ | `client.dm.get_inbox_initial_state(auth_token=...)` | Get inbox state |
170
+ | `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` | Trusted inbox |
171
+ | `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` | Message requests |
172
+ | `client.dm.get_conversation(auth_token=..., conversation_id=...)` | Get messages |
173
+ | `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | DM user updates |
174
+ | `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept request |
175
+
176
+ ## Auto-Pagination
177
+
178
+ Use the `paginate()` and `paginate_pages()` helpers to iterate through all pages automatically:
179
+
180
+ ```python
181
+ from tweetapi import TweetAPI, paginate, paginate_pages
182
+
183
+ client = TweetAPI(api_key="YOUR_API_KEY")
184
+
185
+ # Iterate individual items across all pages
186
+ for user in paginate(
187
+ lambda cursor: client.user.get_followers(user_id="123456", cursor=cursor),
188
+ ):
189
+ print(user["username"])
190
+
191
+ # Iterate full pages (access page-level data)
192
+ for page in paginate_pages(
193
+ lambda cursor: client.explore.search(query="bitcoin", type="Latest", cursor=cursor),
194
+ max_pages=5, # optional: limit number of pages
195
+ ):
196
+ print(f"Got {len(page['data'])} results")
197
+ print(f"Next cursor: {page['pagination']['nextCursor']}")
198
+ ```
199
+
200
+ Works with any paginated endpoint — followers, tweets, search results, list members, community posts, etc.
201
+
202
+ ## Automatic Retry with Backoff
203
+
204
+ The SDK automatically retries on transient errors with exponential backoff:
205
+
206
+ - **429 (Rate Limit)** — waits the `retry_after` duration from the API, then retries
207
+ - **5xx (Server Error)** — retries with exponential backoff + jitter
208
+ - **Network errors** — retries on timeouts and connection failures
209
+ - **4xx (Client Error)** — never retried (400, 401, 403, 404 fail immediately)
210
+
211
+ Default: 3 retries, 2x backoff, 1s initial delay, 30s max delay.
212
+
213
+ ```python
214
+ # Customize retry behavior
215
+ client = TweetAPI(
216
+ api_key="YOUR_API_KEY",
217
+ max_retries=5, # default: 3
218
+ initial_retry_delay=2.0, # default: 1.0 (seconds)
219
+ backoff_multiplier=3.0, # default: 2.0
220
+ max_retry_delay=60.0, # default: 30.0 (seconds)
221
+ )
222
+
223
+ # Disable retries entirely
224
+ client = TweetAPI(api_key="YOUR_API_KEY", max_retries=0)
225
+ ```
226
+
227
+ ### Rate Limit Awareness
228
+
229
+ After a 429 response, the SDK exposes the last known rate limit state:
230
+
231
+ ```python
232
+ print(client.rate_limit_info)
233
+ # {"retry_after": 30, "timestamp": 1712345678.0} — or None if no 429 encountered
234
+ ```
235
+
236
+ ## Error Handling
237
+
238
+ 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:
239
+
240
+ ```python
241
+ from tweetapi import (
242
+ TweetAPI,
243
+ TweetAPIError,
244
+ AuthenticationError,
245
+ RateLimitError,
246
+ NotFoundError,
247
+ ValidationError,
248
+ ServerError,
249
+ NetworkError,
250
+ )
251
+
252
+ client = TweetAPI(api_key="YOUR_API_KEY")
253
+
254
+ try:
255
+ user = client.user.get_by_username(username="elonmusk")
256
+ except RateLimitError as e:
257
+ print(f"Rate limited. Retry in {e.retry_after}s")
258
+ except NotFoundError:
259
+ print("User not found")
260
+ except AuthenticationError:
261
+ print("Invalid API key")
262
+ except ValidationError as e:
263
+ print(f"Bad request: {e.message}")
264
+ except ServerError:
265
+ print("API is having issues, try again later")
266
+ except NetworkError:
267
+ print("Network error — check your connection")
268
+ except TweetAPIError as e:
269
+ print(f"Error [{e.code}]: {e.message}")
270
+ ```
271
+
272
+ Every error includes:
273
+ - `code` — API error code (e.g., `"ACCOUNT_SUSPENDED"`, `"RATE_LIMIT"`)
274
+ - `status_code` — HTTP status code
275
+ - `message` — Human-readable error message
276
+ - `details` — Additional context (field, reason, retry_after, etc.)
277
+
278
+ ## Configuration
279
+
280
+ ```python
281
+ client = TweetAPI(
282
+ api_key="YOUR_API_KEY", # Required
283
+ base_url="https://...", # Optional (default: https://api.tweetapi.com)
284
+ timeout=30, # Optional — single value for both connect + read
285
+ connect_timeout=10.0, # Optional (default: 10s)
286
+ read_timeout=30.0, # Optional (default: 30s)
287
+ max_retries=3, # Optional (default: 3, set 0 to disable)
288
+ backoff_multiplier=2.0, # Optional (default: 2.0)
289
+ initial_retry_delay=1.0, # Optional (default: 1.0s)
290
+ max_retry_delay=30.0, # Optional (default: 30.0s)
291
+ )
292
+
293
+ # You can also pass a tuple for timeout
294
+ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
295
+ ```
296
+
297
+ ## Requirements
298
+
299
+ - Python 3.9+
300
+ - `requests` library
301
+
302
+ ## Links
303
+
304
+ - [Full Documentation](https://tweetapi.com/docs?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
305
+ - [Get API Key (Free)](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
306
+ - [Dashboard](https://tweetapi.com/dashboard?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
307
+ - [Node.js SDK](https://github.com/tweetapi/node)
308
+
309
+ ## License
310
+
311
+ MIT
312
+
313
+ ---
314
+
315
+ *TweetAPI is a third-party service and is not affiliated with X Corp.*