xapi-to 0.1.17 → 0.1.19

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,322 @@
1
+ # TikTok Guide
2
+
3
+ Complete guide for TikTok operations via xAPI — user profiles, videos, comments, search, hashtags, music, live rooms, and recommended feed.
4
+
5
+ > **Dynamic catalog:** These are database-registered third-party APIs under the `tiktok` service. Exact action IDs, HTTP methods, parameters, and response fields can change. Run `search` and `get` before calling; the current schema wins. Examples below reflect one known GET-based version and keep `"method":"GET"` in the input for compatibility.
6
+
7
+ ## Contents
8
+
9
+ - [User data](#user-data)
10
+ - [Video data](#video-data)
11
+ - [Search](#search)
12
+ - [Hashtags](#hashtags)
13
+ - [Music](#music)
14
+ - [Live](#live)
15
+ - [Feed](#feed)
16
+ - [Common workflows](#common-workflows)
17
+ - [Pagination](#pagination-patterns)
18
+ - [API reference](#api-reference)
19
+ - [Error handling](#error-handling)
20
+
21
+ ## User Data
22
+
23
+ ### Get user profile
24
+
25
+ ```bash
26
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_handler__user__profile \
27
+ --input '{"method":"GET","params":{"unique_id":"tiktok"}}'
28
+ ```
29
+
30
+ Look up a user by `unique_id` (username), `user_id` (numeric), or `sec_user_id`. At least one must be provided.
31
+
32
+ Returns `data.data.user` with fields: `uid`, `unique_id`, `nickname`, `signature`, `follower_count`, `following_count`, `total_favorited`, `aweme_count`, `avatar_thumb`, `avatar_medium`, `sec_uid`.
33
+
34
+ **Important:** The user profile returns `sec_uid`, but other TikTok APIs expect the parameter name `sec_user_id`. Pass the value of `sec_uid` as `sec_user_id` when calling other endpoints.
35
+
36
+ ### Get user_id and sec_user_id by username
37
+
38
+ ```bash
39
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_get__user__id__and__sec__user__id__by__username \
40
+ --input '{"method":"GET","params":{"username":"tiktok"}}'
41
+ ```
42
+
43
+ **Important:** Many TikTok actions require `sec_user_id` instead of the username. Use this endpoint or `handler_user_profile` to get it first.
44
+
45
+ ### Get user's videos
46
+
47
+ ```bash
48
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__user__post__videos \
49
+ --input '{"method":"GET","params":{"unique_id":"tiktok","count":10}}'
50
+ ```
51
+
52
+ Can also pass `sec_user_id` instead of `unique_id`. Paginate with `max_cursor` from previous response.
53
+
54
+ Optional parameters:
55
+ - `count` — items per page
56
+ - `sort_type` — sort type
57
+ - `max_cursor` — pagination cursor
58
+
59
+ For faster response with simplified data, use the V3 endpoint: `tiktok.api_v1_tiktok_app_v3_fetch__user__post__videos__v3`.
60
+
61
+ ### Get user's liked videos
62
+
63
+ ```bash
64
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__user__like__videos \
65
+ --input '{"method":"GET","params":{"sec_user_id":"<sec_user_id>","counts":10}}'
66
+ ```
67
+
68
+ Requires `sec_user_id`. Paginate with `max_cursor`. Note: the parameter is `counts` (with 's'), not `count`.
69
+
70
+ ### Get followers / following
71
+
72
+ ```bash
73
+ # Followers
74
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__user__follower__list \
75
+ --input '{"method":"GET","params":{"user_id":"107955","count":20}}'
76
+
77
+ # Following
78
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__user__following__list \
79
+ --input '{"method":"GET","params":{"user_id":"107955","count":20}}'
80
+ ```
81
+
82
+ Pass either `user_id` or `sec_user_id`. Paginate with `min_time` and `page_token` from previous response.
83
+
84
+ ### Get similar user recommendations
85
+
86
+ ```bash
87
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__similar__user__recommendations \
88
+ --input '{"method":"GET","params":{"user_id":"107955"}}'
89
+ ```
90
+
91
+ ## Video Data
92
+
93
+ ### Get video by ID
94
+
95
+ ```bash
96
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__one__video__v2 \
97
+ --input '{"method":"GET","params":{"aweme_id":"<video_id>"}}'
98
+ ```
99
+
100
+ The `aweme_id` is the numeric video ID. Returns full video data including `desc`, `statistics`, `author`, `music`, `video` (with play URLs).
101
+
102
+ ### Get video by share URL
103
+
104
+ ```bash
105
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__one__video__by__share__url__v2 \
106
+ --input '{"method":"GET","params":{"share_url":"https://www.tiktok.com/@user/video/1234567890"}}'
107
+ ```
108
+
109
+ ### Batch get videos
110
+
111
+ ```bash
112
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__multi__video__v2 \
113
+ --input '{"method":"GET","params":{"aweme_ids":"id1,id2,id3"}}'
114
+ ```
115
+
116
+ ### Get video comments
117
+
118
+ ```bash
119
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__video__comments \
120
+ --input '{"method":"GET","params":{"aweme_id":"<video_id>","count":20,"cursor":0}}'
121
+ ```
122
+
123
+ Paginate with `cursor`.
124
+
125
+ ### Get comment replies
126
+
127
+ ```bash
128
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__video__comment__replies \
129
+ --input '{"method":"GET","params":{"item_id":"<video_id>","comment_id":"<comment_id>","count":20,"cursor":0}}'
130
+ ```
131
+
132
+ ## Search
133
+
134
+ ### General search (comprehensive)
135
+
136
+ ```bash
137
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__general__search__result \
138
+ --input '{"method":"GET","params":{"keyword":"cat","count":10}}'
139
+ ```
140
+
141
+ Returns mixed results (videos, users, hashtags). Paginate with `offset`.
142
+
143
+ Optional parameters:
144
+ - `sort_type` — sort type
145
+ - `publish_time` — publish time filter
146
+
147
+ ### Video search
148
+
149
+ ```bash
150
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__video__search__result \
151
+ --input '{"method":"GET","params":{"keyword":"cooking","count":10}}'
152
+ ```
153
+
154
+ Optional: `region`, `sort_type`, `publish_time`. Paginate with `offset`.
155
+
156
+ ### User search
157
+
158
+ ```bash
159
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__user__search__result \
160
+ --input '{"method":"GET","params":{"keyword":"chef","count":10}}'
161
+ ```
162
+
163
+ Optional filters: `user_search_follower_count`, `user_search_profile_type`. Paginate with `offset`.
164
+
165
+ ### Music search
166
+
167
+ ```bash
168
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__music__search__result \
169
+ --input '{"method":"GET","params":{"keyword":"pop","count":10}}'
170
+ ```
171
+
172
+ Optional: `region`, `filter_by`, `sort_type`. Paginate with `offset`.
173
+
174
+ ### Hashtag search
175
+
176
+ ```bash
177
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__hashtag__search__result \
178
+ --input '{"method":"GET","params":{"keyword":"dance","count":10}}'
179
+ ```
180
+
181
+ Paginate with `offset`.
182
+
183
+ ## Hashtags
184
+
185
+ ### Get hashtag details
186
+
187
+ ```bash
188
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__hashtag__detail \
189
+ --input '{"method":"GET","params":{"ch_id":"<hashtag_id>"}}'
190
+ ```
191
+
192
+ ### Get hashtag video list
193
+
194
+ ```bash
195
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__hashtag__video__list \
196
+ --input '{"method":"GET","params":{"ch_id":"<hashtag_id>","count":20,"cursor":0}}'
197
+ ```
198
+
199
+ Paginate with `cursor`.
200
+
201
+ ## Music
202
+
203
+ ### Get music details
204
+
205
+ ```bash
206
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__music__detail \
207
+ --input '{"method":"GET","params":{"music_id":"<music_id>"}}'
208
+ ```
209
+
210
+ ### Get videos using a music
211
+
212
+ ```bash
213
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__music__video__list \
214
+ --input '{"method":"GET","params":{"music_id":"<music_id>","count":20,"cursor":0}}'
215
+ ```
216
+
217
+ Paginate with `cursor`.
218
+
219
+ ## Live
220
+
221
+ ### Get live room info
222
+
223
+ ```bash
224
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__live__room__info \
225
+ --input '{"method":"GET","params":{"room_id":"<room_id>"}}'
226
+ ```
227
+
228
+ ### Check if live room is online
229
+
230
+ ```bash
231
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_check__live__room__online \
232
+ --input '{"method":"GET","params":{"room_id":"<room_id>"}}'
233
+ ```
234
+
235
+ ### Batch check live rooms online
236
+
237
+ ```bash
238
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_check__live__room__online__batch \
239
+ --input '{"method":"GET","params":{"room_ids":"id1,id2,id3"}}'
240
+ ```
241
+
242
+ ### Get live search results
243
+
244
+ ```bash
245
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__live__search__result \
246
+ --input '{"method":"GET","params":{"keyword":"gaming"}}'
247
+ ```
248
+
249
+ ## Feed
250
+
251
+ ### Get home feed (recommended videos)
252
+
253
+ ```bash
254
+ npx xapi-to call tiktok.api_v1_tiktok_app_v3_fetch__home__feed \
255
+ --input '{"method":"GET","params":{}}'
256
+ ```
257
+
258
+ Returns recommended "For You" page videos. **Note:** This endpoint may return empty results depending on account/region configuration.
259
+
260
+ ## Common Workflows
261
+
262
+ ### Research a TikTok creator
263
+
264
+ 1. Look up user: `tiktok...handler__user__profile` with `unique_id` → get `uid`, `sec_user_id`, follower stats
265
+ 2. Get videos: `tiktok...fetch__user__post__videos` → browse recent content
266
+ 3. Check engagement: view `statistics` in each video (play count, likes, comments, shares)
267
+
268
+ ### Analyze a TikTok video
269
+
270
+ 1. Get video: `tiktok...fetch__one__video__v2` with `aweme_id` → full video data
271
+ 2. Read comments: `tiktok...fetch__video__comments` → top comments
272
+ 3. Get replies: `tiktok...fetch__video__comment__replies` → comment threads
273
+
274
+ ### Discover content by hashtag
275
+
276
+ 1. Search hashtags: `tiktok...fetch__hashtag__search__result` with `keyword` → find hashtag IDs
277
+ 2. Get details: `tiktok...fetch__hashtag__detail` with `ch_id` → view count, video count
278
+ 3. Browse videos: `tiktok...fetch__hashtag__video__list` → videos using this hashtag
279
+
280
+ ## Pagination Patterns
281
+
282
+ | Pattern | Endpoints | How to use |
283
+ |---------|-----------|------------|
284
+ | `max_cursor` | user videos, liked videos | Pass `max_cursor` from previous response |
285
+ | `cursor` | comments, hashtag videos, music videos | Pass `cursor` from previous response |
286
+ | `offset` | all search endpoints | Increment by `count` each page |
287
+ | `min_time` + `page_token` | follower/following lists | Pass both from previous response |
288
+
289
+ ## API Reference
290
+
291
+ | API (prefix: `tiktok.api_v1_tiktok_app_v3_`) | Description | Key Params |
292
+ |---|---|---|
293
+ | `handler__user__profile` | Get user profile | `unique_id` or `user_id` or `sec_user_id` |
294
+ | `get__user__id__and__sec__user__id__by__username` | Get IDs by username | `username` |
295
+ | `fetch__user__post__videos` | User's videos | `unique_id` or `sec_user_id`, `count`, `max_cursor` |
296
+ | `fetch__user__post__videos__v3` | User's videos (simplified) | `unique_id` or `sec_user_id`, `count`, `max_cursor` |
297
+ | `fetch__user__like__videos` | User's liked videos | `sec_user_id`, `counts`, `max_cursor` |
298
+ | `fetch__user__follower__list` | User's followers | `user_id` or `sec_user_id`, `count` |
299
+ | `fetch__user__following__list` | User's following | `user_id` or `sec_user_id`, `count` |
300
+ | `fetch__one__video__v2` | Single video | `aweme_id` |
301
+ | `fetch__one__video__by__share__url__v2` | Video by share URL | `share_url` |
302
+ | `fetch__multi__video__v2` | Batch get videos | `aweme_ids` |
303
+ | `fetch__video__comments` | Video comments | `aweme_id`, `count`, `cursor` |
304
+ | `fetch__video__comment__replies` | Comment replies | `item_id`, `comment_id`, `count`, `cursor` |
305
+ | `fetch__general__search__result` | General search | `keyword`, `count`, `offset` |
306
+ | `fetch__video__search__result` | Video search | `keyword`, `count`, `offset` |
307
+ | `fetch__user__search__result` | User search | `keyword`, `count`, `offset` |
308
+ | `fetch__music__search__result` | Music search | `keyword`, `count`, `offset` |
309
+ | `fetch__hashtag__search__result` | Hashtag search | `keyword`, `count`, `offset` |
310
+ | `fetch__hashtag__detail` | Hashtag details | `ch_id` |
311
+ | `fetch__hashtag__video__list` | Hashtag videos | `ch_id`, `count`, `cursor` |
312
+ | `fetch__music__detail` | Music details | `music_id` |
313
+ | `fetch__music__video__list` | Music videos | `music_id`, `count`, `cursor` |
314
+ | `fetch__live__room__info` | Live room info | `room_id` |
315
+ | `check__live__room__online` | Check live online | `room_id` |
316
+ | `fetch__home__feed` | Home feed | — |
317
+
318
+ ## Error Handling
319
+
320
+ - **Missing sec_user_id** → Use `handler_user_profile` or `get_user_id_and_sec_user_id_by_username` to get it first
321
+ - **Empty results** → Check that `aweme_id`, `ch_id`, or `music_id` is valid
322
+ - **Pagination exhausted** → When `has_more` is `0` or `false`, no more pages available
@@ -0,0 +1,276 @@
1
+ # Twitter / X Guide
2
+
3
+ Complete guide for Twitter operations via xAPI — reading data, downloading tweet videos, posting tweets, replying, and OAuth setup.
4
+
5
+ > **Upstream provider:** All `twitter.*` capabilities accept an optional `provider` — `"x"` (fapi.uk, the default) or `"twitter"` (legacy upstream). The response is normalized to an identical structure regardless of provider, so you normally omit it. Pass `"provider":"twitter"` only to force the legacy upstream, e.g. `--input '{"screen_name":"elonmusk","provider":"twitter"}'`.
6
+
7
+ ## Contents
8
+
9
+ - [Read Twitter data](#reading-twitter-data-no-oauth-needed)
10
+ - [Download a tweet video](#download-a-tweet-video)
11
+ - [Post and mutate with OAuth](#posting-tweets-oauth-required)
12
+ - [Common workflows](#common-workflows)
13
+ - [Pagination reference](#pagination-reference)
14
+ - [API reference](#api-reference)
15
+ - [Error handling](#error-handling)
16
+
17
+ ## Reading Twitter Data (no OAuth needed)
18
+
19
+ ### Look up a user by @handle
20
+
21
+ ```bash
22
+ npx xapi-to call twitter.user_by_screen_name --input '{"screen_name":"elonmusk"}'
23
+ ```
24
+
25
+ Returns `rest_id` (numeric user ID), `name`, `screen_name`, `followers_count`, `statuses_count`, etc.
26
+
27
+ **Important:** Most Twitter actions require the numeric `user_id` (called `rest_id` in the response), not the @handle. Always look up the user first to get the ID.
28
+
29
+ ### Get a user's recent tweets
30
+
31
+ ```bash
32
+ npx xapi-to call twitter.user_tweets --input '{"user_id":"44196397"}'
33
+ ```
34
+
35
+ Each tweet includes: `id`, `full_text`, `created_at`, `favorite_count`, `retweet_count`, `reply_count`, `views_count`, `media`, `author`, and `quoted_tweet` if applicable.
36
+
37
+ Paginate with the previous response's `data.cursors.bottom`:
38
+
39
+ ```bash
40
+ npx xapi-to call twitter.user_tweets \
41
+ --input '{"user_id":"44196397","cursor":"<cursors.bottom>"}'
42
+ ```
43
+
44
+ ### Get a user's tweets and replies
45
+
46
+ ```bash
47
+ npx xapi-to call twitter.user_tweets_and_replies --input '{"user_id":"44196397"}'
48
+ ```
49
+
50
+ Similar to `twitter.user_tweets`, but the timeline also includes the user's replies to other tweets and conversation threads they participate in. Each item includes the same fields: `id`, `full_text`, `created_at`, `favorite_count`, `retweet_count`, `reply_count`, `views_count`, `media`, `author`, and `quoted_tweet` if applicable.
51
+
52
+ **When to choose which:**
53
+
54
+ - `twitter.user_tweets` — only the user's own posts. Use for content/timeline of original tweets.
55
+ - `twitter.user_tweets_and_replies` — posts plus replies and conversation participants. Use to monitor a user's reply activity or full timeline.
56
+
57
+ **Filter tip:** because conversation entries can contain tweets from other authors, filter by `author.id === user_id` if you only want the monitored user's content.
58
+
59
+ Pagination uses the same `cursor` → `data.cursors.bottom` pattern as `twitter.user_tweets`.
60
+
61
+ For `twitter.user_tweets` and `twitter.user_tweets_and_replies`, set `"cache":true` to use the fast cache when available and skip the normal upstream call. Cached results can be less fresh; keep the default `false` when freshness matters.
62
+
63
+ ### Get a specific tweet and its replies
64
+
65
+ ```bash
66
+ npx xapi-to call twitter.tweet_detail --input '{"tweet_id":"2035526376468394305"}'
67
+ ```
68
+
69
+ To load more replies, pass the previous response's `data.cursors.bottom` as `cursor`:
70
+
71
+ ```bash
72
+ npx xapi-to call twitter.tweet_detail \
73
+ --input '{"tweet_id":"2035526376468394305","cursor":"<cursors.bottom>"}'
74
+ ```
75
+
76
+ Paginated pages commonly contain more `replies` but no main tweet, so `data.tweet` may be `null` when `cursor` is present.
77
+
78
+ ### Download a tweet video
79
+
80
+ Use the bundled downloader with either a complete status URL or its numeric tweet ID. Resolve `<xapi-skill-directory>` to the directory containing this guide's parent `SKILL.md`:
81
+
82
+ ```bash
83
+ bash <xapi-skill-directory>/scripts/download_tweet_videos.sh \
84
+ 'https://x.com/NousResearch/status/2084325600643445095'
85
+ ```
86
+
87
+ Pass an optional existing output directory as the second argument; otherwise files are written to the current directory. A single video is named `tweet-<tweet-id>.mp4`; multiple videos are numbered `tweet-<tweet-id>-1.mp4`, `-2.mp4`, and so on. The script includes videos in the main, quoted, and retweeted tweets, deduplicates identical media URLs, and refuses to overwrite any existing output.
88
+
89
+ The script verifies that the deployed `twitter.tweet_detail` schema exposes `video_url` before making the paid call. It omits `provider` to retain automatic failover from the default `x` upstream to the legacy `twitter` upstream on transient failures. The response's `data.provider` identifies the upstream that served it; explicitly setting `provider` would pin that upstream and disable failover.
90
+
91
+ Each download is written to a same-directory temporary file, required to have MIME type `video/mp4`, optionally checked with `ffprobe`, and only renamed to its final path after every media file passes. Failures clean up temporary files, so a partial transfer is never published as the final MP4.
92
+
93
+ `data.tweet.media[].url` and `preview_url` are preview images; do not download them as MP4. The optional `video_info.variants` retains the original MP4 and HLS variants when a specific rendition is needed. `call --output` is not appropriate because the xAPI action returns JSON metadata rather than video bytes; the bundled script downloads each resolved `video_url` with `curl`.
94
+
95
+ ### Read an X Article (long-form post)
96
+
97
+ Some tweets are long-form **X Articles**. `twitter.tweet_detail` detects them and returns the full normalized article directly in `data.tweet.article`; no raw GraphQL call or `fieldToggles` parameter is needed.
98
+
99
+ ```bash
100
+ npx xapi-to call twitter.tweet_detail --input '{"tweet_id":"<tweet_id>"}'
101
+ ```
102
+
103
+ The normalized `article` object contains:
104
+
105
+ - `id`, `title`, and `preview_text`
106
+ - `text` — full plain text
107
+ - `markdown` — full text with headings, lists, quotes, code blocks, and inline links preserved
108
+ - `cover_image` — URL and optional dimensions
109
+ - `links` — deduplicated external links in appearance order
110
+ - `first_published_at` and `modified_at` — ISO 8601 timestamps when available
111
+
112
+ Use the **tweet ID** from the share URL (`x.com/<user>/status/<tweet_id>` or `x.com/<user>/article/<tweet_id>`), not an internal article ID.
113
+
114
+ ### Search tweets
115
+
116
+ ```bash
117
+ npx xapi-to call twitter.search --input '{"raw_query":"AI agents","count":20}'
118
+ ```
119
+
120
+ For `provider: "x"` (the default), structured advanced-search filters are also available:
121
+
122
+ ```bash
123
+ npx xapi-to call twitter.search --input '{
124
+ "raw_query":"AI",
125
+ "from":"OpenAI",
126
+ "mentioning":"AnthropicAI",
127
+ "phrase":"AI agents",
128
+ "since":"2026-08-01",
129
+ "until":"2026-08-05",
130
+ "min_likes":100,
131
+ "min_replies":10,
132
+ "min_retweets":20,
133
+ "count":20
134
+ }'
135
+ ```
136
+
137
+ Supported structured filters: `from`, `to`, `mentioning`, `phrase`, `any`, `none`, `tag`, `since`, `until`, `min_replies`, `min_likes`, `min_retweets`, and `count`. `sort_by` accepts `Top`, `Latest` (default), `People`, `Photos`, or `Videos`; the default `x` provider maps both media-specific values to its combined Media search. Dates use `YYYY-MM-DD`; `until` is exclusive. Paginate with `cursor` from `data.cursor_bottom`.
138
+
139
+ ### Get user's media posts
140
+
141
+ ```bash
142
+ npx xapi-to call twitter.user_media --input '{"user_id":"44196397"}'
143
+ ```
144
+
145
+ Paginate with `cursor` from the previous response's `data.cursor_bottom`. Both the default `x` provider and legacy `twitter` provider are supported.
146
+
147
+ ### Get followers / following
148
+
149
+ ```bash
150
+ npx xapi-to call twitter.followers --input '{"user_id":"44196397"}'
151
+ npx xapi-to call twitter.following --input '{"user_id":"44196397"}'
152
+ ```
153
+
154
+ ### Get retweeters
155
+
156
+ ```bash
157
+ npx xapi-to call twitter.retweeters --input '{"tweet_id":"1234567890"}'
158
+ ```
159
+
160
+ ## Posting Tweets (OAuth required)
161
+
162
+ Posting, replying, quoting, liking, retweeting, and deleting require OAuth. A saved binding provides technical authorization, not standing user consent: confirm the current content and target before a write, and obtain explicit confirmation before destructive or bulk actions.
163
+
164
+ ### Step 1: Bind Twitter OAuth
165
+
166
+ ```bash
167
+ npx xapi-to oauth bind --provider twitter
168
+ ```
169
+
170
+ This opens a browser for the user to authorize. After authorization, the binding is saved to the API key.
171
+
172
+ Verify:
173
+
174
+ ```bash
175
+ npx xapi-to oauth status
176
+ ```
177
+
178
+ Should show `tweet.write` in scopes.
179
+
180
+ ### Step 2: Post a tweet
181
+
182
+ ```bash
183
+ npx xapi-to call x-official.2_tweets --method POST \
184
+ --input '{"body":{"text":"Hello from my AI agent!"}}'
185
+ ```
186
+
187
+ **Character limit:** 280 characters (140 CJK characters). Each CJK character counts as 2.
188
+
189
+ ### Reply to a tweet
190
+
191
+ ```bash
192
+ npx xapi-to call x-official.2_tweets --method POST \
193
+ --input '{"body":{"text":"Great point!","reply":{"in_reply_to_tweet_id":"2035526376468394305"}}}'
194
+ ```
195
+
196
+ ### Quote tweet
197
+
198
+ ```bash
199
+ npx xapi-to call x-official.2_tweets --method POST \
200
+ --input '{"body":{"text":"Worth reading 👇","quote_tweet_id":"2035526376468394305"}}'
201
+ ```
202
+
203
+ ### Delete a tweet
204
+
205
+ ```bash
206
+ npx xapi-to call x-official.2_tweets_id --method DELETE \
207
+ --input '{"pathParams":{"id":"2036012345678901234"}}'
208
+ ```
209
+
210
+ ### Like a tweet
211
+
212
+ ```bash
213
+ npx xapi-to call x-official.2_users_id_likes --method POST \
214
+ --input '{"pathParams":{"id":"<your_user_id>"},"body":{"tweet_id":"2035526376468394305"}}'
215
+ ```
216
+
217
+ ### Retweet
218
+
219
+ ```bash
220
+ npx xapi-to call x-official.2_users_id_retweets --method POST \
221
+ --input '{"pathParams":{"id":"<your_user_id>"},"body":{"tweet_id":"2035526376468394305"}}'
222
+ ```
223
+
224
+ ## Common Workflows
225
+
226
+ ### Research and tweet
227
+
228
+ 1. Search the web: `web.search.realtime` → get latest news
229
+ 2. Summarize: `ai.text.summarize` → create a concise summary
230
+ 3. Post: `x-official.2_tweets` POST → tweet the summary
231
+
232
+ ### Monitor and reply
233
+
234
+ 1. Get user activity: `twitter.user_tweets` (originals only) or `twitter.user_tweets_and_replies` (includes replies) → check latest posts
235
+ 2. Get tweet detail: `twitter.tweet_detail` → read the thread
236
+ 3. Reply: `x-official.2_tweets` POST with `reply` → respond
237
+
238
+ ## Pagination Reference
239
+
240
+ | Capability | Next cursor field | Next request input |
241
+ |---|---|---|
242
+ | `twitter.user_tweets` | `data.cursors.bottom` | `cursor` |
243
+ | `twitter.user_tweets_and_replies` | `data.cursors.bottom` | `cursor` |
244
+ | `twitter.tweet_detail` replies | `data.cursors.bottom` | `cursor` |
245
+ | `twitter.user_media` | `data.cursor_bottom` | `cursor` |
246
+ | `twitter.search` | `data.cursor_bottom` | `cursor` |
247
+ | `twitter.followers` | `data.cursor_bottom` | `cursor` |
248
+ | `twitter.following` | `data.cursor_bottom` | `cursor` |
249
+ | `twitter.retweeters` | `data.cursor_bottom` | `cursor` |
250
+
251
+ Omit `cursor` for the first page. Stop when the relevant bottom cursor is absent or empty.
252
+
253
+ ## API Reference
254
+
255
+ | API | Method | Description |
256
+ |-----------|--------|-------------|
257
+ | `twitter.user_by_screen_name` | — | Look up user by @handle |
258
+ | `twitter.user_tweets` | — | Get and paginate user's recent tweets |
259
+ | `twitter.user_tweets_and_replies` | — | Get and paginate user's tweets and replies |
260
+ | `twitter.user_media` | — | Get and paginate user's media posts |
261
+ | `twitter.tweet_detail` | — | Get tweet, full X Article content, and paginated replies |
262
+ | `twitter.search` | — | Search tweets with cursor and advanced filters |
263
+ | `twitter.followers` | — | Get user's followers |
264
+ | `twitter.following` | — | Get user's following |
265
+ | `twitter.retweeters` | — | Get tweet retweeters |
266
+ | `x-official.2_tweets` | POST | Post a tweet |
267
+ | `x-official.2_tweets_id` | DELETE | Delete a tweet |
268
+ | `x-official.2_users_id_likes` | POST | Like a tweet |
269
+ | `x-official.2_users_id_retweets` | POST | Retweet |
270
+
271
+ ## Error Handling
272
+
273
+ - **OAuth Required** → Run `npx xapi-to oauth bind --provider twitter`
274
+ - **403 Forbidden** → Twitter account may have restrictions; check account status
275
+ - **Tweet too long** → Shorten to 280 chars (140 CJK)
276
+ - **User not found** → Check the screen_name spelling