tweetapi 2.2.0__tar.gz → 2.2.1__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.
- {tweetapi-2.2.0 → tweetapi-2.2.1}/PKG-INFO +49 -58
- {tweetapi-2.2.0 → tweetapi-2.2.1}/README.md +47 -56
- {tweetapi-2.2.0 → tweetapi-2.2.1}/pyproject.toml +2 -2
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/__init__.py +1 -1
- {tweetapi-2.2.0 → tweetapi-2.2.1}/.gitignore +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/client.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/errors.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/pagination.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/py.typed +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/__init__.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/auth.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/community.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/explore.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/interaction.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/list_.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/post.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/profile.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/space.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/tweet.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/unencrypted_dm.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/user.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/resources/xchat.py +0 -0
- {tweetapi-2.2.0 → tweetapi-2.2.1}/tweetapi/types.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tweetapi
|
|
3
|
-
Version: 2.2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: Python SDK for TweetAPI's Twitter/X data and account API
|
|
5
5
|
Project-URL: Homepage, https://tweetapi.com?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
|
|
6
6
|
Project-URL: Documentation, https://tweetapi.com/docs?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
|
|
7
7
|
Project-URL: Repository, https://github.com/tweetapi/python
|
|
@@ -30,9 +30,7 @@ Description-Content-Type: text/markdown
|
|
|
30
30
|
|
|
31
31
|
# TweetAPI Python SDK
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Access tweets, user profiles, followers, analytics, and full interaction capabilities. 70+ endpoints with built-in error handling and type hints.
|
|
33
|
+
`tweetapi` is the Python SDK for [TweetAPI](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk). It provides methods for users, tweets, posts, profiles, interactions, lists, communities, Spaces, search, authentication, and direct messages.
|
|
36
34
|
|
|
37
35
|
## Install
|
|
38
36
|
|
|
@@ -40,7 +38,7 @@ Access tweets, user profiles, followers, analytics, and full interaction capabil
|
|
|
40
38
|
pip install tweetapi
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
## Quick
|
|
41
|
+
## Quick start
|
|
44
42
|
|
|
45
43
|
```python
|
|
46
44
|
from tweetapi import TweetAPI
|
|
@@ -49,7 +47,7 @@ client = TweetAPI(api_key="YOUR_API_KEY")
|
|
|
49
47
|
|
|
50
48
|
# Get a user profile
|
|
51
49
|
user = client.user.get_by_username(username="elonmusk")
|
|
52
|
-
print(user["data"]["followerCount"])
|
|
50
|
+
print(user["data"]["followerCount"])
|
|
53
51
|
|
|
54
52
|
# Search tweets
|
|
55
53
|
results = client.explore.search(query="bitcoin", type="Latest")
|
|
@@ -62,21 +60,18 @@ next_page = client.user.get_followers(
|
|
|
62
60
|
)
|
|
63
61
|
```
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
[Create an API key](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk) with 100 included requests. No credit card is required.
|
|
66
64
|
|
|
67
|
-
##
|
|
65
|
+
## SDK behavior
|
|
68
66
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
- **Split timeouts** — separate connect and read timeouts
|
|
76
|
-
- **Single dependency** — `requests` only
|
|
77
|
-
- **Python 3.9+** compatible
|
|
67
|
+
- Public methods have type annotations, and response models use `TypedDict`.
|
|
68
|
+
- The client retries rate limits, server errors, timeouts, and connection failures.
|
|
69
|
+
- `paginate()` yields items from cursor-based responses; `paginate_pages()` yields full response pages.
|
|
70
|
+
- HTTP errors map to exception classes such as `RateLimitError` and `NotFoundError`.
|
|
71
|
+
- Timeouts can use one value or separate connect and read values.
|
|
72
|
+
- The package supports Python 3.9+ and depends on `requests`.
|
|
78
73
|
|
|
79
|
-
## API
|
|
74
|
+
## API reference
|
|
80
75
|
|
|
81
76
|
### User
|
|
82
77
|
|
|
@@ -105,7 +100,7 @@ next_page = client.user.get_followers(
|
|
|
105
100
|
|--------|-------------|
|
|
106
101
|
| `client.tweet.get_details_and_conversation(tweet_id=...)` | Get tweet details and replies |
|
|
107
102
|
| `client.tweet.get_details_by_ids(ids=...)` | Get multiple tweets (max 200) |
|
|
108
|
-
| `client.tweet.get_retweets(tweet_id=...)` | Get who retweeted |
|
|
103
|
+
| `client.tweet.get_retweets(tweet_id=...)` | Get users who retweeted |
|
|
109
104
|
| `client.tweet.get_quotes(tweet_id=...)` | Get quote tweets |
|
|
110
105
|
| `client.tweet.translate(tweet_id=..., dst_lang=...)` | Translate a tweet |
|
|
111
106
|
|
|
@@ -173,8 +168,8 @@ next_page = client.user.get_followers(
|
|
|
173
168
|
| `client.community.create_quote_with_media(...)` | Quote post with media |
|
|
174
169
|
| `client.community.reply_post(...)` | Reply to community post |
|
|
175
170
|
| `client.community.reply_post_with_media(...)` | Reply with media |
|
|
176
|
-
| `client.community.join(auth_token=..., community_id=...)` | Join |
|
|
177
|
-
| `client.community.leave(auth_token=..., community_id=...)` | Leave |
|
|
171
|
+
| `client.community.join(auth_token=..., community_id=...)` | Join a community |
|
|
172
|
+
| `client.community.leave(auth_token=..., community_id=...)` | Leave a community |
|
|
178
173
|
|
|
179
174
|
### Space
|
|
180
175
|
|
|
@@ -187,24 +182,24 @@ next_page = client.user.get_followers(
|
|
|
187
182
|
|
|
188
183
|
| Method | Description |
|
|
189
184
|
|--------|-------------|
|
|
190
|
-
| `client.explore.search(query=..., type=...)` | Search tweets
|
|
185
|
+
| `client.explore.search(query=..., type=...)` | Search tweets, users, photos, or videos |
|
|
191
186
|
|
|
192
187
|
### Auth
|
|
193
188
|
|
|
194
189
|
| Method | Description |
|
|
195
190
|
|--------|-------------|
|
|
196
|
-
| `client.auth.login(username=..., password=..., proxy=..., country=...)` | Log in
|
|
191
|
+
| `client.auth.login(username=..., password=..., proxy=..., country=...)` | Log in and return auth tokens |
|
|
197
192
|
|
|
198
193
|
`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.
|
|
199
194
|
|
|
200
|
-
### X Chat (
|
|
195
|
+
### X Chat (encrypted DMs)
|
|
201
196
|
|
|
202
197
|
| Method | Description |
|
|
203
198
|
|--------|-------------|
|
|
204
199
|
| `client.xchat.setup(auth_token=..., user_id=..., pin=...)` | Initialize encrypted DMs |
|
|
205
200
|
| `client.xchat.get_conversations(auth_token=...)` | List conversations |
|
|
206
201
|
| `client.xchat.send(auth_token=..., recipient_id=..., message=...)` | Send message |
|
|
207
|
-
| `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get history |
|
|
202
|
+
| `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get conversation history |
|
|
208
203
|
| `client.xchat.can_dm(auth_token=..., user_ids=...)` | Check DM availability |
|
|
209
204
|
|
|
210
205
|
### Unencrypted DMs
|
|
@@ -214,13 +209,13 @@ next_page = client.user.get_followers(
|
|
|
214
209
|
| `client.dm.send_dm(auth_token=..., conversation_id=..., text=..., proxy=...)` | Send DM |
|
|
215
210
|
| `client.dm.get_dm_permissions(auth_token=..., recipient_ids=...)` | Check permissions |
|
|
216
211
|
| `client.dm.get_inbox_initial_state(auth_token=...)` | Get inbox state |
|
|
217
|
-
| `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` |
|
|
218
|
-
| `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` |
|
|
212
|
+
| `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` | Get the trusted inbox |
|
|
213
|
+
| `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` | Get message requests |
|
|
219
214
|
| `client.dm.get_conversation(auth_token=..., conversation_id=...)` | Get messages |
|
|
220
|
-
| `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | DM user updates |
|
|
221
|
-
| `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept request |
|
|
215
|
+
| `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | Get DM user updates |
|
|
216
|
+
| `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept a conversation request |
|
|
222
217
|
|
|
223
|
-
## Posting and
|
|
218
|
+
## Posting and profile media
|
|
224
219
|
|
|
225
220
|
Tweet media accepts an existing TweetAPI media ID, a URL, or inline base64 data:
|
|
226
221
|
|
|
@@ -260,7 +255,7 @@ client.profile.remove_banner(auth_token="AUTH_TOKEN")
|
|
|
260
255
|
client.profile.set_privacy(auth_token="AUTH_TOKEN", is_private=True)
|
|
261
256
|
```
|
|
262
257
|
|
|
263
|
-
|
|
258
|
+
Use `client.list` for list mutations. The older helpers under `client.interaction` remain available:
|
|
264
259
|
|
|
265
260
|
```python
|
|
266
261
|
created = client.list.create(
|
|
@@ -293,9 +288,9 @@ client.community.create_quote_with_media(
|
|
|
293
288
|
)
|
|
294
289
|
```
|
|
295
290
|
|
|
296
|
-
##
|
|
291
|
+
## Pagination
|
|
297
292
|
|
|
298
|
-
|
|
293
|
+
`paginate()` yields individual items. `paginate_pages()` yields each full response page:
|
|
299
294
|
|
|
300
295
|
```python
|
|
301
296
|
from tweetapi import TweetAPI, paginate, paginate_pages
|
|
@@ -317,18 +312,16 @@ for page in paginate_pages(
|
|
|
317
312
|
print(f"Next cursor: {page['pagination']['nextCursor']}")
|
|
318
313
|
```
|
|
319
314
|
|
|
320
|
-
|
|
315
|
+
Each helper accepts a callable that takes a cursor and returns a response with `data` and `pagination.nextCursor`. Use `max_pages` to limit the number of fetched pages.
|
|
321
316
|
|
|
322
|
-
##
|
|
317
|
+
## Retries
|
|
323
318
|
|
|
324
|
-
The
|
|
319
|
+
The client retries these transient failures:
|
|
325
320
|
|
|
326
|
-
-
|
|
327
|
-
-
|
|
328
|
-
- **Network errors** — retries on timeouts and connection failures
|
|
329
|
-
- **4xx (Client Error)** — never retried (400, 401, 403, 404 fail immediately)
|
|
321
|
+
- For a 429 response, it waits for `RateLimitError.retry_after` seconds, up to `max_retry_delay`.
|
|
322
|
+
- For a 5xx response, timeout, or connection failure, it uses exponential backoff with up to 25% jitter.
|
|
330
323
|
|
|
331
|
-
|
|
324
|
+
By default, the client makes up to 3 retries. Its base delay starts at 1 second, doubles after each attempt, and is capped at 30 seconds. Other 4xx responses are not retried.
|
|
332
325
|
|
|
333
326
|
```python
|
|
334
327
|
# Customize retry behavior
|
|
@@ -344,18 +337,17 @@ client = TweetAPI(
|
|
|
344
337
|
client = TweetAPI(api_key="YOUR_API_KEY", max_retries=0)
|
|
345
338
|
```
|
|
346
339
|
|
|
347
|
-
### Rate
|
|
340
|
+
### Rate-limit state
|
|
348
341
|
|
|
349
|
-
After a 429 response, the
|
|
342
|
+
After a 429 response, `client.rate_limit_info` records the retry delay and the time the response was received:
|
|
350
343
|
|
|
351
344
|
```python
|
|
352
345
|
print(client.rate_limit_info)
|
|
353
|
-
# {"retry_after": 30, "timestamp": 1712345678.0} — or None if no 429 encountered
|
|
354
346
|
```
|
|
355
347
|
|
|
356
|
-
## Error
|
|
348
|
+
## Error handling
|
|
357
349
|
|
|
358
|
-
The
|
|
350
|
+
The client raises retryable errors after it exhausts the configured retries. It raises other errors from the first response:
|
|
359
351
|
|
|
360
352
|
```python
|
|
361
353
|
from tweetapi import (
|
|
@@ -389,11 +381,12 @@ except TweetAPIError as e:
|
|
|
389
381
|
print(f"Error [{e.code}]: {e.message}")
|
|
390
382
|
```
|
|
391
383
|
|
|
392
|
-
Every error includes:
|
|
393
|
-
|
|
394
|
-
- `
|
|
395
|
-
- `
|
|
396
|
-
- `
|
|
384
|
+
Every error includes these attributes:
|
|
385
|
+
|
|
386
|
+
- `code`: API error code, such as `"ACCOUNT_SUSPENDED"` or `"RATE_LIMIT"`
|
|
387
|
+
- `status_code`: HTTP status code
|
|
388
|
+
- `message`: human-readable error message
|
|
389
|
+
- `details`: response context such as a field, reason, or retry delay
|
|
397
390
|
|
|
398
391
|
## Configuration
|
|
399
392
|
|
|
@@ -401,7 +394,7 @@ Every error includes:
|
|
|
401
394
|
client = TweetAPI(
|
|
402
395
|
api_key="YOUR_API_KEY", # Required
|
|
403
396
|
base_url="https://...", # Optional (default: https://api.tweetapi.com)
|
|
404
|
-
timeout=30, # Optional
|
|
397
|
+
timeout=30, # Optional; one value for connect and read
|
|
405
398
|
connect_timeout=10.0, # Optional (default: 10s)
|
|
406
399
|
read_timeout=30.0, # Optional (default: 30s)
|
|
407
400
|
max_retries=3, # Optional (default: 3, set 0 to disable)
|
|
@@ -421,8 +414,8 @@ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
|
|
|
421
414
|
|
|
422
415
|
## Links
|
|
423
416
|
|
|
424
|
-
- [
|
|
425
|
-
- [
|
|
417
|
+
- [Documentation](https://tweetapi.com/docs?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
418
|
+
- [Create an API key](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
426
419
|
- [Dashboard](https://tweetapi.com/dashboard?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
427
420
|
- [Node.js SDK](https://github.com/tweetapi/node)
|
|
428
421
|
|
|
@@ -430,6 +423,4 @@ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
|
|
|
430
423
|
|
|
431
424
|
MIT
|
|
432
425
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
*TweetAPI is a third-party service and is not affiliated with X Corp.*
|
|
426
|
+
TweetAPI is a third-party service and is not affiliated with X Corp.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# TweetAPI Python SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Access tweets, user profiles, followers, analytics, and full interaction capabilities. 70+ endpoints with built-in error handling and type hints.
|
|
3
|
+
`tweetapi` is the Python SDK for [TweetAPI](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk). It provides methods for users, tweets, posts, profiles, interactions, lists, communities, Spaces, search, authentication, and direct messages.
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
@@ -10,7 +8,7 @@ Access tweets, user profiles, followers, analytics, and full interaction capabil
|
|
|
10
8
|
pip install tweetapi
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
## Quick
|
|
11
|
+
## Quick start
|
|
14
12
|
|
|
15
13
|
```python
|
|
16
14
|
from tweetapi import TweetAPI
|
|
@@ -19,7 +17,7 @@ client = TweetAPI(api_key="YOUR_API_KEY")
|
|
|
19
17
|
|
|
20
18
|
# Get a user profile
|
|
21
19
|
user = client.user.get_by_username(username="elonmusk")
|
|
22
|
-
print(user["data"]["followerCount"])
|
|
20
|
+
print(user["data"]["followerCount"])
|
|
23
21
|
|
|
24
22
|
# Search tweets
|
|
25
23
|
results = client.explore.search(query="bitcoin", type="Latest")
|
|
@@ -32,21 +30,18 @@ next_page = client.user.get_followers(
|
|
|
32
30
|
)
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
[Create an API key](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk) with 100 included requests. No credit card is required.
|
|
36
34
|
|
|
37
|
-
##
|
|
35
|
+
## SDK behavior
|
|
38
36
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
- **Split timeouts** — separate connect and read timeouts
|
|
46
|
-
- **Single dependency** — `requests` only
|
|
47
|
-
- **Python 3.9+** compatible
|
|
37
|
+
- Public methods have type annotations, and response models use `TypedDict`.
|
|
38
|
+
- The client retries rate limits, server errors, timeouts, and connection failures.
|
|
39
|
+
- `paginate()` yields items from cursor-based responses; `paginate_pages()` yields full response pages.
|
|
40
|
+
- HTTP errors map to exception classes such as `RateLimitError` and `NotFoundError`.
|
|
41
|
+
- Timeouts can use one value or separate connect and read values.
|
|
42
|
+
- The package supports Python 3.9+ and depends on `requests`.
|
|
48
43
|
|
|
49
|
-
## API
|
|
44
|
+
## API reference
|
|
50
45
|
|
|
51
46
|
### User
|
|
52
47
|
|
|
@@ -75,7 +70,7 @@ next_page = client.user.get_followers(
|
|
|
75
70
|
|--------|-------------|
|
|
76
71
|
| `client.tweet.get_details_and_conversation(tweet_id=...)` | Get tweet details and replies |
|
|
77
72
|
| `client.tweet.get_details_by_ids(ids=...)` | Get multiple tweets (max 200) |
|
|
78
|
-
| `client.tweet.get_retweets(tweet_id=...)` | Get who retweeted |
|
|
73
|
+
| `client.tweet.get_retweets(tweet_id=...)` | Get users who retweeted |
|
|
79
74
|
| `client.tweet.get_quotes(tweet_id=...)` | Get quote tweets |
|
|
80
75
|
| `client.tweet.translate(tweet_id=..., dst_lang=...)` | Translate a tweet |
|
|
81
76
|
|
|
@@ -143,8 +138,8 @@ next_page = client.user.get_followers(
|
|
|
143
138
|
| `client.community.create_quote_with_media(...)` | Quote post with media |
|
|
144
139
|
| `client.community.reply_post(...)` | Reply to community post |
|
|
145
140
|
| `client.community.reply_post_with_media(...)` | Reply with media |
|
|
146
|
-
| `client.community.join(auth_token=..., community_id=...)` | Join |
|
|
147
|
-
| `client.community.leave(auth_token=..., community_id=...)` | Leave |
|
|
141
|
+
| `client.community.join(auth_token=..., community_id=...)` | Join a community |
|
|
142
|
+
| `client.community.leave(auth_token=..., community_id=...)` | Leave a community |
|
|
148
143
|
|
|
149
144
|
### Space
|
|
150
145
|
|
|
@@ -157,24 +152,24 @@ next_page = client.user.get_followers(
|
|
|
157
152
|
|
|
158
153
|
| Method | Description |
|
|
159
154
|
|--------|-------------|
|
|
160
|
-
| `client.explore.search(query=..., type=...)` | Search tweets
|
|
155
|
+
| `client.explore.search(query=..., type=...)` | Search tweets, users, photos, or videos |
|
|
161
156
|
|
|
162
157
|
### Auth
|
|
163
158
|
|
|
164
159
|
| Method | Description |
|
|
165
160
|
|--------|-------------|
|
|
166
|
-
| `client.auth.login(username=..., password=..., proxy=..., country=...)` | Log in
|
|
161
|
+
| `client.auth.login(username=..., password=..., proxy=..., country=...)` | Log in and return auth tokens |
|
|
167
162
|
|
|
168
163
|
`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.
|
|
169
164
|
|
|
170
|
-
### X Chat (
|
|
165
|
+
### X Chat (encrypted DMs)
|
|
171
166
|
|
|
172
167
|
| Method | Description |
|
|
173
168
|
|--------|-------------|
|
|
174
169
|
| `client.xchat.setup(auth_token=..., user_id=..., pin=...)` | Initialize encrypted DMs |
|
|
175
170
|
| `client.xchat.get_conversations(auth_token=...)` | List conversations |
|
|
176
171
|
| `client.xchat.send(auth_token=..., recipient_id=..., message=...)` | Send message |
|
|
177
|
-
| `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get history |
|
|
172
|
+
| `client.xchat.get_history(auth_token=..., conversation_id=...)` | Get conversation history |
|
|
178
173
|
| `client.xchat.can_dm(auth_token=..., user_ids=...)` | Check DM availability |
|
|
179
174
|
|
|
180
175
|
### Unencrypted DMs
|
|
@@ -184,13 +179,13 @@ next_page = client.user.get_followers(
|
|
|
184
179
|
| `client.dm.send_dm(auth_token=..., conversation_id=..., text=..., proxy=...)` | Send DM |
|
|
185
180
|
| `client.dm.get_dm_permissions(auth_token=..., recipient_ids=...)` | Check permissions |
|
|
186
181
|
| `client.dm.get_inbox_initial_state(auth_token=...)` | Get inbox state |
|
|
187
|
-
| `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` |
|
|
188
|
-
| `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` |
|
|
182
|
+
| `client.dm.get_inbox_trusted(auth_token=..., cursor=...)` | Get the trusted inbox |
|
|
183
|
+
| `client.dm.get_inbox_untrusted(auth_token=..., cursor=...)` | Get message requests |
|
|
189
184
|
| `client.dm.get_conversation(auth_token=..., conversation_id=...)` | Get messages |
|
|
190
|
-
| `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | DM user updates |
|
|
191
|
-
| `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept request |
|
|
185
|
+
| `client.dm.get_dm_user_updates(auth_token=..., cursor=...)` | Get DM user updates |
|
|
186
|
+
| `client.dm.accept_conversation(auth_token=..., conversation_id=...)` | Accept a conversation request |
|
|
192
187
|
|
|
193
|
-
## Posting and
|
|
188
|
+
## Posting and profile media
|
|
194
189
|
|
|
195
190
|
Tweet media accepts an existing TweetAPI media ID, a URL, or inline base64 data:
|
|
196
191
|
|
|
@@ -230,7 +225,7 @@ client.profile.remove_banner(auth_token="AUTH_TOKEN")
|
|
|
230
225
|
client.profile.set_privacy(auth_token="AUTH_TOKEN", is_private=True)
|
|
231
226
|
```
|
|
232
227
|
|
|
233
|
-
|
|
228
|
+
Use `client.list` for list mutations. The older helpers under `client.interaction` remain available:
|
|
234
229
|
|
|
235
230
|
```python
|
|
236
231
|
created = client.list.create(
|
|
@@ -263,9 +258,9 @@ client.community.create_quote_with_media(
|
|
|
263
258
|
)
|
|
264
259
|
```
|
|
265
260
|
|
|
266
|
-
##
|
|
261
|
+
## Pagination
|
|
267
262
|
|
|
268
|
-
|
|
263
|
+
`paginate()` yields individual items. `paginate_pages()` yields each full response page:
|
|
269
264
|
|
|
270
265
|
```python
|
|
271
266
|
from tweetapi import TweetAPI, paginate, paginate_pages
|
|
@@ -287,18 +282,16 @@ for page in paginate_pages(
|
|
|
287
282
|
print(f"Next cursor: {page['pagination']['nextCursor']}")
|
|
288
283
|
```
|
|
289
284
|
|
|
290
|
-
|
|
285
|
+
Each helper accepts a callable that takes a cursor and returns a response with `data` and `pagination.nextCursor`. Use `max_pages` to limit the number of fetched pages.
|
|
291
286
|
|
|
292
|
-
##
|
|
287
|
+
## Retries
|
|
293
288
|
|
|
294
|
-
The
|
|
289
|
+
The client retries these transient failures:
|
|
295
290
|
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
- **Network errors** — retries on timeouts and connection failures
|
|
299
|
-
- **4xx (Client Error)** — never retried (400, 401, 403, 404 fail immediately)
|
|
291
|
+
- For a 429 response, it waits for `RateLimitError.retry_after` seconds, up to `max_retry_delay`.
|
|
292
|
+
- For a 5xx response, timeout, or connection failure, it uses exponential backoff with up to 25% jitter.
|
|
300
293
|
|
|
301
|
-
|
|
294
|
+
By default, the client makes up to 3 retries. Its base delay starts at 1 second, doubles after each attempt, and is capped at 30 seconds. Other 4xx responses are not retried.
|
|
302
295
|
|
|
303
296
|
```python
|
|
304
297
|
# Customize retry behavior
|
|
@@ -314,18 +307,17 @@ client = TweetAPI(
|
|
|
314
307
|
client = TweetAPI(api_key="YOUR_API_KEY", max_retries=0)
|
|
315
308
|
```
|
|
316
309
|
|
|
317
|
-
### Rate
|
|
310
|
+
### Rate-limit state
|
|
318
311
|
|
|
319
|
-
After a 429 response, the
|
|
312
|
+
After a 429 response, `client.rate_limit_info` records the retry delay and the time the response was received:
|
|
320
313
|
|
|
321
314
|
```python
|
|
322
315
|
print(client.rate_limit_info)
|
|
323
|
-
# {"retry_after": 30, "timestamp": 1712345678.0} — or None if no 429 encountered
|
|
324
316
|
```
|
|
325
317
|
|
|
326
|
-
## Error
|
|
318
|
+
## Error handling
|
|
327
319
|
|
|
328
|
-
The
|
|
320
|
+
The client raises retryable errors after it exhausts the configured retries. It raises other errors from the first response:
|
|
329
321
|
|
|
330
322
|
```python
|
|
331
323
|
from tweetapi import (
|
|
@@ -359,11 +351,12 @@ except TweetAPIError as e:
|
|
|
359
351
|
print(f"Error [{e.code}]: {e.message}")
|
|
360
352
|
```
|
|
361
353
|
|
|
362
|
-
Every error includes:
|
|
363
|
-
|
|
364
|
-
- `
|
|
365
|
-
- `
|
|
366
|
-
- `
|
|
354
|
+
Every error includes these attributes:
|
|
355
|
+
|
|
356
|
+
- `code`: API error code, such as `"ACCOUNT_SUSPENDED"` or `"RATE_LIMIT"`
|
|
357
|
+
- `status_code`: HTTP status code
|
|
358
|
+
- `message`: human-readable error message
|
|
359
|
+
- `details`: response context such as a field, reason, or retry delay
|
|
367
360
|
|
|
368
361
|
## Configuration
|
|
369
362
|
|
|
@@ -371,7 +364,7 @@ Every error includes:
|
|
|
371
364
|
client = TweetAPI(
|
|
372
365
|
api_key="YOUR_API_KEY", # Required
|
|
373
366
|
base_url="https://...", # Optional (default: https://api.tweetapi.com)
|
|
374
|
-
timeout=30, # Optional
|
|
367
|
+
timeout=30, # Optional; one value for connect and read
|
|
375
368
|
connect_timeout=10.0, # Optional (default: 10s)
|
|
376
369
|
read_timeout=30.0, # Optional (default: 30s)
|
|
377
370
|
max_retries=3, # Optional (default: 3, set 0 to disable)
|
|
@@ -391,8 +384,8 @@ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
|
|
|
391
384
|
|
|
392
385
|
## Links
|
|
393
386
|
|
|
394
|
-
- [
|
|
395
|
-
- [
|
|
387
|
+
- [Documentation](https://tweetapi.com/docs?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
388
|
+
- [Create an API key](https://tweetapi.com?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
396
389
|
- [Dashboard](https://tweetapi.com/dashboard?utm_source=github&utm_medium=readme&utm_campaign=python-sdk)
|
|
397
390
|
- [Node.js SDK](https://github.com/tweetapi/node)
|
|
398
391
|
|
|
@@ -400,6 +393,4 @@ client = TweetAPI(api_key="YOUR_API_KEY", timeout=(5, 30)) # (connect, read)
|
|
|
400
393
|
|
|
401
394
|
MIT
|
|
402
395
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
*TweetAPI is a third-party service and is not affiliated with X Corp.*
|
|
396
|
+
TweetAPI is a third-party service and is not affiliated with X Corp.
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tweetapi"
|
|
7
|
-
version = "2.2.
|
|
8
|
-
description = "
|
|
7
|
+
version = "2.2.1"
|
|
8
|
+
description = "Python SDK for TweetAPI's Twitter/X data and account API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|