@xquik/tweetclaw 1.6.5 → 1.6.7
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.
- package/README.md +22 -13
- package/dist/api-spec.d.ts +3 -0
- package/dist/api-spec.js +1427 -0
- package/dist/api-spec.js.map +1 -0
- package/dist/commands/xstatus.d.ts +17 -0
- package/dist/commands/xstatus.js +52 -0
- package/dist/commands/xstatus.js.map +1 -0
- package/dist/commands/xtrends.d.ts +16 -0
- package/dist/commands/xtrends.js +39 -0
- package/dist/commands/xtrends.js.map +1 -0
- package/dist/index.d.ts +107 -0
- package/dist/index.js +249 -0
- package/dist/index.js.map +1 -0
- package/dist/mpp.d.ts +7 -0
- package/dist/mpp.js +39 -0
- package/dist/mpp.js.map +1 -0
- package/dist/request.d.ts +7 -0
- package/dist/request.js +88 -0
- package/dist/request.js.map +1 -0
- package/dist/services/event-poller.d.ts +7 -0
- package/dist/services/event-poller.js +69 -0
- package/dist/services/event-poller.js.map +1 -0
- package/dist/tools/catalog.d.ts +17 -0
- package/dist/tools/catalog.js +110 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/explore.d.ts +5 -0
- package/dist/tools/explore.js +28 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/result.d.ts +5 -0
- package/dist/tools/result.js +15 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/tweetclaw.d.ts +13 -0
- package/dist/tools/tweetclaw.js +62 -0
- package/dist/tools/tweetclaw.js.map +1 -0
- package/dist/truncate.d.ts +3 -0
- package/dist/truncate.js +25 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +7 -8
- package/package.json +19 -18
- package/skills/tweetclaw/SKILL.md +33 -42
- package/src/api-spec.ts +480 -12
- package/src/index.ts +135 -36
- package/src/mpp.ts +9 -11
- package/src/request.ts +27 -2
- package/src/tools/catalog.ts +145 -0
- package/src/tools/explore.ts +18 -44
- package/src/tools/result.ts +19 -0
- package/src/tools/tweetclaw.ts +49 -296
- package/src/types.ts +19 -0
- package/src/tools/executor.ts +0 -125
package/dist/api-spec.js
ADDED
|
@@ -0,0 +1,1427 @@
|
|
|
1
|
+
const RESPONSE_SUCCESS = '{ success: true }';
|
|
2
|
+
const DESCRIPTION_PAGINATION_CURSOR = 'Pagination cursor';
|
|
3
|
+
const DESCRIPTION_STYLE_USERNAME = 'X username of cached style';
|
|
4
|
+
const DESCRIPTION_EXPORT_FORMAT = 'Export format (csv, json, md, md-document, pdf, txt, xlsx)';
|
|
5
|
+
const CATEGORY_X_ACCOUNTS = 'x-accounts';
|
|
6
|
+
const MPP_PRICE_CALL = '$0.00015/call';
|
|
7
|
+
const MPP_PRICE_COMMUNITY = '$0.00015/community';
|
|
8
|
+
const MPP_PRICE_FOLLOW_CHECK = '$0.00105/call';
|
|
9
|
+
const MPP_PRICE_MEDIA = '$0.00015/media';
|
|
10
|
+
const MPP_PRICE_TREND = '$0.00045/call';
|
|
11
|
+
const MPP_PRICE_TWEET = '$0.00015/tweet';
|
|
12
|
+
const MPP_PRICE_USER = '$0.00015/user';
|
|
13
|
+
const PAGINATION_PARAMS = [
|
|
14
|
+
{ description: 'Max items per page', in: 'query', name: 'limit', required: false, type: 'number' },
|
|
15
|
+
{ description: DESCRIPTION_PAGINATION_CURSOR, in: 'query', name: 'after', required: false, type: 'string' },
|
|
16
|
+
];
|
|
17
|
+
const EXTRACTION_SEARCH_PARAMS = [
|
|
18
|
+
{ description: 'Filter tweets by author username (tweet_search_extractor)', in: 'body', name: 'fromUser', required: false, type: 'string' },
|
|
19
|
+
{ description: 'Filter tweets to a specific user (tweet_search_extractor)', in: 'body', name: 'toUser', required: false, type: 'string' },
|
|
20
|
+
{ description: 'Filter tweets mentioning a user (tweet_search_extractor)', in: 'body', name: 'mentioning', required: false, type: 'string' },
|
|
21
|
+
{ description: 'Language code filter, e.g. en, tr (tweet_search_extractor)', in: 'body', name: 'language', required: false, type: 'string' },
|
|
22
|
+
{ description: 'Start date YYYY-MM-DD (tweet_search_extractor)', in: 'body', name: 'sinceDate', required: false, type: 'string' },
|
|
23
|
+
{ description: 'End date YYYY-MM-DD (tweet_search_extractor)', in: 'body', name: 'untilDate', required: false, type: 'string' },
|
|
24
|
+
{ description: 'Filter by media type: images, videos, gifs, media (tweet_search_extractor)', in: 'body', name: 'mediaType', required: false, type: 'string' },
|
|
25
|
+
{ description: 'Minimum likes threshold (tweet_search_extractor)', in: 'body', name: 'minFaves', required: false, type: 'number' },
|
|
26
|
+
{ description: 'Minimum retweets threshold (tweet_search_extractor)', in: 'body', name: 'minRetweets', required: false, type: 'number' },
|
|
27
|
+
{ description: 'Minimum replies threshold (tweet_search_extractor)', in: 'body', name: 'minReplies', required: false, type: 'number' },
|
|
28
|
+
{ description: 'Only verified authors (tweet_search_extractor)', in: 'body', name: 'verifiedOnly', required: false, type: 'boolean' },
|
|
29
|
+
{ description: 'Control reply inclusion (tweet_search_extractor): include, exclude, only', in: 'body', name: 'replies', required: false, type: 'string' },
|
|
30
|
+
{ description: 'Control retweet inclusion (tweet_search_extractor): include, exclude, only', in: 'body', name: 'retweets', required: false, type: 'string' },
|
|
31
|
+
{ description: 'Exact phrase match (tweet_search_extractor)', in: 'body', name: 'exactPhrase', required: false, type: 'string' },
|
|
32
|
+
{ description: 'Comma-separated words to exclude (tweet_search_extractor)', in: 'body', name: 'excludeWords', required: false, type: 'string' },
|
|
33
|
+
{ description: 'Raw X search operators (tweet_search_extractor)', in: 'body', name: 'advancedQuery', required: false, type: 'string' },
|
|
34
|
+
];
|
|
35
|
+
const PARAM_STYLE_USERNAME = { description: DESCRIPTION_STYLE_USERNAME, in: 'path', name: 'username', required: true, type: 'string' };
|
|
36
|
+
const PARAM_EXPORT_FORMAT = { description: DESCRIPTION_EXPORT_FORMAT, in: 'query', name: 'format', required: false, type: 'string' };
|
|
37
|
+
const PARAM_DRAW_ID = { description: 'Draw public ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
38
|
+
const PARAM_EXTRACTION_ID = { description: 'Extraction public ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
39
|
+
const PARAM_X_ACCOUNT = { description: 'X account (@username or account ID)', in: 'body', name: 'account', required: true, type: 'string' };
|
|
40
|
+
const PARAM_X_ACCOUNT_ID = { description: 'X account ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
41
|
+
const DESCRIPTION_EVENT_TYPES = 'tweet.new, tweet.reply, tweet.quote, tweet.retweet';
|
|
42
|
+
const PARAM_EVENT_TYPES_REQUIRED = { description: `Event types: ${DESCRIPTION_EVENT_TYPES}`, in: 'body', name: 'eventTypes', required: true, type: 'string[]' };
|
|
43
|
+
const PARAM_EVENT_TYPES_OPTIONAL = { description: `Updated event types: ${DESCRIPTION_EVENT_TYPES}`, in: 'body', name: 'eventTypes', required: false, type: 'string[]' };
|
|
44
|
+
const PARAM_MONITOR_ID = { description: 'Monitor ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
45
|
+
const PARAM_WEBHOOK_ID = { description: 'Webhook ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
46
|
+
const PARAM_TWEET_ID = { description: 'Tweet ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
47
|
+
const PARAM_COMMUNITY_ID = { description: 'Community ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
48
|
+
const PARAMS_TWEET_ACTION = [PARAM_TWEET_ID, PARAM_X_ACCOUNT];
|
|
49
|
+
const PARAMS_COMMUNITY_ACTION = [PARAM_COMMUNITY_ID, PARAM_X_ACCOUNT];
|
|
50
|
+
const PARAM_USER_ID_FOLLOW = { description: 'User ID to follow', in: 'path', name: 'id', required: true, type: 'string' };
|
|
51
|
+
const PARAM_USER_ID_UNFOLLOW = { description: 'User ID to unfollow', in: 'path', name: 'id', required: true, type: 'string' };
|
|
52
|
+
const PARAM_USER_ID_REMOVE_FOLLOWER = { description: 'User ID to remove from your followers', in: 'path', name: 'id', required: true, type: 'string' };
|
|
53
|
+
const PARAM_MEDIA_URL = { description: 'URL to download media from (alternative to file, HTTPS only)', in: 'body', name: 'url', required: false, type: 'string' };
|
|
54
|
+
const PARAM_KEYWORD_MONITOR_ID = { description: 'Keyword monitor ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
55
|
+
const PARAM_CURSOR = { description: 'Pagination cursor from previous response', in: 'query', name: 'cursor', required: false, type: 'string' };
|
|
56
|
+
const PARAM_AFTER_ALIAS = { description: 'Legacy cursor alias. Prefer cursor.', in: 'query', name: 'after', required: false, type: 'string' };
|
|
57
|
+
const PARAM_PAGE_SIZE_20 = { description: 'Upper bound for items per page (20-200, default 20)', in: 'query', name: 'pageSize', required: false, type: 'number' };
|
|
58
|
+
const PARAM_PAGE_SIZE_200 = { description: 'Upper bound for items per page (20-200, default 200)', in: 'query', name: 'pageSize', required: false, type: 'number' };
|
|
59
|
+
const PARAM_LIMIT_ALIAS = { description: 'Legacy page size upper-bound alias. Prefer pageSize.', in: 'query', name: 'limit', required: false, type: 'number' };
|
|
60
|
+
const PARAM_QUERY_TYPE = { description: 'Sort order: Latest or Top', in: 'query', name: 'queryType', required: false, type: 'string' };
|
|
61
|
+
const PARAM_SEARCH_QUERY = { description: 'Search query', in: 'query', name: 'q', required: true, type: 'string' };
|
|
62
|
+
const PARAM_SINCE_TIME = { description: 'Filter results since this Unix timestamp in seconds', in: 'query', name: 'sinceTime', required: false, type: 'number' };
|
|
63
|
+
const PARAM_UNTIL_TIME = { description: 'Filter results until this Unix timestamp in seconds', in: 'query', name: 'untilTime', required: false, type: 'number' };
|
|
64
|
+
const PARAM_USER_ID = { description: 'User ID or username', in: 'path', name: 'id', required: true, type: 'string' };
|
|
65
|
+
const PARAM_LIST_ID = { description: 'List ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
66
|
+
const RESPONSE_TWEET = '{ id, text, created?, retweet_count?, reply_count?, like_count?, quote_count?, view_count?, bookmark_count?, media?, url?, lang?, is_reply?, is_note_tweet?, is_quote_status?, in_reply_to_id?, conversation_id?, source?, entities?, quoted_tweet?, author? }';
|
|
67
|
+
const RESPONSE_TWEET_BASIC = '{ id, text, created?, retweet_count?, reply_count?, like_count?, quote_count?, view_count?, bookmark_count?, media?, url?, lang?, is_reply?, in_reply_to_id?, conversation_id?, source?, entities?, author? }';
|
|
68
|
+
const RESPONSE_TWEETS_PAGINATED = `{ tweets: [${RESPONSE_TWEET}], has_more, next_cursor }`;
|
|
69
|
+
const RESPONSE_USER = '{ id, username, name, followers?, following?, verified?, profile_picture?, cover_picture?, description?, location?, created?, statuses_count?, media_count?, can_dm? }';
|
|
70
|
+
const RESPONSE_USERS_PAGINATED = `{ users: [${RESPONSE_USER}], has_more, next_cursor }`;
|
|
71
|
+
const RESPONSE_COMMUNITY_ACTION = '{ communityId, communityName, success: true }';
|
|
72
|
+
const CATEGORY_SUPPORT = 'support';
|
|
73
|
+
const CATEGORY_X_WRITE = 'x-write';
|
|
74
|
+
const PARAM_TICKET_ID = { description: 'Ticket public ID', in: 'path', name: 'id', required: true, type: 'string' };
|
|
75
|
+
const API_SPEC = [
|
|
76
|
+
// --- Account ---
|
|
77
|
+
{
|
|
78
|
+
category: 'account',
|
|
79
|
+
free: true,
|
|
80
|
+
method: 'GET',
|
|
81
|
+
path: '/api/v1/account',
|
|
82
|
+
responseShape: '{ email, locale, xUsername, subscription, usage }',
|
|
83
|
+
summary: 'Get current account info and subscription status',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
agentProhibited: true,
|
|
87
|
+
category: 'account',
|
|
88
|
+
free: true,
|
|
89
|
+
method: 'PATCH',
|
|
90
|
+
parameters: [
|
|
91
|
+
{ description: 'Locale code (en, tr, es)', in: 'body', name: 'locale', required: true, type: 'string' },
|
|
92
|
+
],
|
|
93
|
+
path: '/api/v1/account',
|
|
94
|
+
responseShape: RESPONSE_SUCCESS,
|
|
95
|
+
summary: 'Update account settings such as locale',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
agentProhibited: true,
|
|
99
|
+
category: 'account',
|
|
100
|
+
free: true,
|
|
101
|
+
method: 'PUT',
|
|
102
|
+
parameters: [
|
|
103
|
+
{ description: 'X username without @', in: 'body', name: 'username', required: true, type: 'string' },
|
|
104
|
+
],
|
|
105
|
+
path: '/api/v1/account/x-identity',
|
|
106
|
+
responseShape: '{ success: true, xUsername }',
|
|
107
|
+
summary: 'Set or update linked X username',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
agentProhibited: true,
|
|
111
|
+
category: 'account',
|
|
112
|
+
free: true,
|
|
113
|
+
method: 'GET',
|
|
114
|
+
path: '/api/v1/api-keys',
|
|
115
|
+
responseShape: '{ keys: [{ id, name, prefix, isActive, createdAt, lastUsedAt? }] }',
|
|
116
|
+
summary: 'List all API keys for the account',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
agentProhibited: true,
|
|
120
|
+
category: 'account',
|
|
121
|
+
free: true,
|
|
122
|
+
method: 'POST',
|
|
123
|
+
parameters: [
|
|
124
|
+
{ description: 'Display name for the key', in: 'body', name: 'name', required: false, type: 'string' },
|
|
125
|
+
],
|
|
126
|
+
path: '/api/v1/api-keys',
|
|
127
|
+
responseShape: '{ id, name, prefix, fullKey, createdAt }',
|
|
128
|
+
summary: 'Create a new API key',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
agentProhibited: true,
|
|
132
|
+
category: 'account',
|
|
133
|
+
free: true,
|
|
134
|
+
method: 'DELETE',
|
|
135
|
+
parameters: [
|
|
136
|
+
{ description: 'API key ID to revoke', in: 'path', name: 'id', required: true, type: 'string' },
|
|
137
|
+
],
|
|
138
|
+
path: '/api/v1/api-keys/:id',
|
|
139
|
+
responseShape: RESPONSE_SUCCESS,
|
|
140
|
+
summary: 'Revoke an API key by ID',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
agentProhibited: true,
|
|
144
|
+
category: 'account',
|
|
145
|
+
free: true,
|
|
146
|
+
method: 'POST',
|
|
147
|
+
path: '/api/v1/subscribe',
|
|
148
|
+
responseShape: '{ url }',
|
|
149
|
+
summary: 'Get checkout or billing portal URL',
|
|
150
|
+
},
|
|
151
|
+
// --- Composition ---
|
|
152
|
+
{
|
|
153
|
+
category: 'composition',
|
|
154
|
+
free: true,
|
|
155
|
+
method: 'POST',
|
|
156
|
+
parameters: [
|
|
157
|
+
{ description: 'Workflow step: compose, refine, or score', in: 'body', name: 'step', required: true, type: 'string' },
|
|
158
|
+
{ description: 'Tweet topic (compose, refine)', in: 'body', name: 'topic', required: false, type: 'string' },
|
|
159
|
+
{ description: 'Optimization goal: engagement, followers, authority, conversation', in: 'body', name: 'goal', required: false, type: 'string' },
|
|
160
|
+
{ description: 'Tweet draft text to evaluate (score)', in: 'body', name: 'draft', required: false, type: 'string' },
|
|
161
|
+
{ description: 'Desired tone for the tweet (refine)', in: 'body', name: 'tone', required: false, type: 'string' },
|
|
162
|
+
{ description: 'Cached style username for voice matching (compose)', in: 'body', name: 'styleUsername', required: false, type: 'string' },
|
|
163
|
+
{ description: 'Extra context or URLs (refine)', in: 'body', name: 'additionalContext', required: false, type: 'string' },
|
|
164
|
+
{ description: 'Desired call to action (refine)', in: 'body', name: 'callToAction', required: false, type: 'string' },
|
|
165
|
+
{ description: 'Media type: photo, video, none (refine)', in: 'body', name: 'mediaType', required: false, type: 'string' },
|
|
166
|
+
{ description: 'Whether a link is attached (score)', in: 'body', name: 'hasLink', required: false, type: 'boolean' },
|
|
167
|
+
{ description: 'Whether media is attached (score)', in: 'body', name: 'hasMedia', required: false, type: 'boolean' },
|
|
168
|
+
],
|
|
169
|
+
path: '/api/v1/compose',
|
|
170
|
+
responseShape: '{ contentRules, scorerWeights, followUpQuestions, ... }',
|
|
171
|
+
summary: 'Compose, refine, or score a tweet using algorithm data',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
category: 'composition',
|
|
175
|
+
free: true,
|
|
176
|
+
method: 'GET',
|
|
177
|
+
parameters: [
|
|
178
|
+
{ description: 'Max items to return', in: 'query', name: 'limit', required: false, type: 'number' },
|
|
179
|
+
{ description: 'Cursor for pagination', in: 'query', name: 'afterCursor', required: false, type: 'string' },
|
|
180
|
+
],
|
|
181
|
+
path: '/api/v1/drafts',
|
|
182
|
+
responseShape: '{ drafts: [{ id, text, topic?, goal?, createdAt }], hasMore, nextCursor? }',
|
|
183
|
+
summary: 'List saved tweet drafts with pagination',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
category: 'composition',
|
|
187
|
+
free: true,
|
|
188
|
+
method: 'POST',
|
|
189
|
+
parameters: [
|
|
190
|
+
{ description: 'Draft tweet text', in: 'body', name: 'text', required: true, type: 'string' },
|
|
191
|
+
{ description: 'Tweet topic', in: 'body', name: 'topic', required: false, type: 'string' },
|
|
192
|
+
{ description: 'Optimization goal: engagement, followers, authority, conversation', in: 'body', name: 'goal', required: false, type: 'string' },
|
|
193
|
+
],
|
|
194
|
+
path: '/api/v1/drafts',
|
|
195
|
+
responseShape: '{ id, text, topic?, goal?, createdAt, updatedAt }',
|
|
196
|
+
summary: 'Save a new tweet draft',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
category: 'composition',
|
|
200
|
+
free: true,
|
|
201
|
+
method: 'GET',
|
|
202
|
+
parameters: [
|
|
203
|
+
{ description: 'Draft ID', in: 'path', name: 'id', required: true, type: 'string' },
|
|
204
|
+
],
|
|
205
|
+
path: '/api/v1/drafts/:id',
|
|
206
|
+
responseShape: '{ id, text, topic?, goal?, createdAt, updatedAt }',
|
|
207
|
+
summary: 'Get a single draft by ID',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
category: 'composition',
|
|
211
|
+
free: true,
|
|
212
|
+
method: 'DELETE',
|
|
213
|
+
parameters: [
|
|
214
|
+
{ description: 'Draft ID to delete', in: 'path', name: 'id', required: true, type: 'string' },
|
|
215
|
+
],
|
|
216
|
+
path: '/api/v1/drafts/:id',
|
|
217
|
+
responseShape: '204 No Content',
|
|
218
|
+
summary: 'Delete a draft by ID',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
category: 'composition',
|
|
222
|
+
free: true,
|
|
223
|
+
method: 'GET',
|
|
224
|
+
path: '/api/v1/styles',
|
|
225
|
+
responseShape: '{ styles: [{ xUsername, tweetCount, isOwnAccount, fetchedAt }] }',
|
|
226
|
+
summary: 'List all cached writing style profiles',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
category: 'composition',
|
|
230
|
+
free: true,
|
|
231
|
+
method: 'POST',
|
|
232
|
+
parameters: [
|
|
233
|
+
{ description: 'X username to analyze', in: 'body', name: 'username', required: true, type: 'string' },
|
|
234
|
+
],
|
|
235
|
+
path: '/api/v1/styles',
|
|
236
|
+
responseShape: '{ xUsername, tweetCount, isOwnAccount, fetchedAt, tweets }',
|
|
237
|
+
summary: 'Analyze and cache a writing style from recent tweets',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
category: 'composition',
|
|
241
|
+
free: true,
|
|
242
|
+
method: 'GET',
|
|
243
|
+
parameters: [PARAM_STYLE_USERNAME],
|
|
244
|
+
path: '/api/v1/styles/:username',
|
|
245
|
+
responseShape: '{ xUsername, tweetCount, isOwnAccount, fetchedAt, tweets }',
|
|
246
|
+
summary: 'Get a cached style profile by username',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
category: 'composition',
|
|
250
|
+
free: true,
|
|
251
|
+
method: 'PUT',
|
|
252
|
+
parameters: [
|
|
253
|
+
{ description: 'Style label (username key)', in: 'path', name: 'username', required: true, type: 'string' },
|
|
254
|
+
{ description: 'Display label for the style', in: 'body', name: 'label', required: true, type: 'string' },
|
|
255
|
+
{ description: 'Array of tweet objects with text field', in: 'body', name: 'tweets', required: true, type: 'array' },
|
|
256
|
+
],
|
|
257
|
+
path: '/api/v1/styles/:username',
|
|
258
|
+
responseShape: '{ xUsername, tweetCount, isOwnAccount, fetchedAt, tweets }',
|
|
259
|
+
summary: 'Create or update a style profile with custom tweets',
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
category: 'composition',
|
|
263
|
+
free: true,
|
|
264
|
+
method: 'DELETE',
|
|
265
|
+
parameters: [
|
|
266
|
+
{ description: 'X username of style to delete', in: 'path', name: 'username', required: true, type: 'string' },
|
|
267
|
+
],
|
|
268
|
+
path: '/api/v1/styles/:username',
|
|
269
|
+
responseShape: '204 No Content',
|
|
270
|
+
summary: 'Delete a cached style profile',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
category: 'composition',
|
|
274
|
+
free: false,
|
|
275
|
+
method: 'GET',
|
|
276
|
+
parameters: [PARAM_STYLE_USERNAME],
|
|
277
|
+
path: '/api/v1/styles/:username/performance',
|
|
278
|
+
responseShape: '{ xUsername, tweetCount, tweets: [{ id, text, likeCount, retweetCount, ... }] }',
|
|
279
|
+
summary: 'Get engagement metrics for cached style tweets',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
category: 'composition',
|
|
283
|
+
free: true,
|
|
284
|
+
method: 'GET',
|
|
285
|
+
parameters: [
|
|
286
|
+
{ description: 'First username to compare', in: 'query', name: 'username1', required: true, type: 'string' },
|
|
287
|
+
{ description: 'Second username to compare', in: 'query', name: 'username2', required: true, type: 'string' },
|
|
288
|
+
],
|
|
289
|
+
path: '/api/v1/styles/compare',
|
|
290
|
+
responseShape: '{ style1: { xUsername, tweets, ... }, style2: { xUsername, tweets, ... } }',
|
|
291
|
+
summary: 'Compare two cached writing style profiles',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
category: 'composition',
|
|
295
|
+
free: true,
|
|
296
|
+
method: 'GET',
|
|
297
|
+
parameters: [
|
|
298
|
+
{ description: 'Filter by category (general, tech, dev, etc.)', in: 'query', name: 'category', required: false, type: 'string' },
|
|
299
|
+
{ description: 'Max items to return (1-100, default 50)', in: 'query', name: 'limit', required: false, type: 'number' },
|
|
300
|
+
{ description: 'Lookback window in hours (1-72, default 6)', in: 'query', name: 'hours', required: false, type: 'number' },
|
|
301
|
+
{ description: 'Region filter (US, GB, TR, ES, DE, FR, JP, IN, BR, CA, MX, global)', in: 'query', name: 'region', required: false, type: 'string' },
|
|
302
|
+
{ description: 'Source filter (github, google_trends, hacker_news, polymarket, reddit, trustmrr, wikipedia)', in: 'query', name: 'source', required: false, type: 'string' },
|
|
303
|
+
{ description: DESCRIPTION_PAGINATION_CURSOR, in: 'query', name: 'after', required: false, type: 'string' },
|
|
304
|
+
],
|
|
305
|
+
path: '/api/v1/radar',
|
|
306
|
+
responseShape: '{ items: [{ title, url?, score, category, source, region, publishedAt }], hasMore, nextCursor? }',
|
|
307
|
+
summary: 'Get trending topics from curated radar sources',
|
|
308
|
+
},
|
|
309
|
+
// --- Extraction ---
|
|
310
|
+
{
|
|
311
|
+
category: 'extraction',
|
|
312
|
+
free: true,
|
|
313
|
+
method: 'GET',
|
|
314
|
+
parameters: [...PAGINATION_PARAMS],
|
|
315
|
+
path: '/api/v1/draws',
|
|
316
|
+
responseShape: '{ draws: [{ id, tweetUrl, status, totalEntries, validEntries, createdAt }], hasMore, nextCursor? }',
|
|
317
|
+
summary: 'List giveaway draws with pagination',
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
category: 'extraction',
|
|
321
|
+
free: false,
|
|
322
|
+
method: 'POST',
|
|
323
|
+
parameters: [
|
|
324
|
+
{ description: 'URL of the giveaway tweet', in: 'body', name: 'tweetUrl', required: true, type: 'string' },
|
|
325
|
+
{ description: 'Number of winners to pick', in: 'body', name: 'winnerCount', required: false, type: 'number' },
|
|
326
|
+
{ description: 'Winner eligibility filters (follow, like, retweet, etc.)', in: 'body', name: 'filters', required: false, type: 'object' },
|
|
327
|
+
],
|
|
328
|
+
path: '/api/v1/draws',
|
|
329
|
+
responseShape: '{ id, tweetId, totalEntries, validEntries, winners: [{ position, authorUsername, tweetId, isBackup }] }',
|
|
330
|
+
summary: 'Run a giveaway draw on a tweet',
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
category: 'extraction',
|
|
334
|
+
free: true,
|
|
335
|
+
method: 'GET',
|
|
336
|
+
parameters: [PARAM_DRAW_ID],
|
|
337
|
+
path: '/api/v1/draws/:id',
|
|
338
|
+
responseShape: '{ draw: { id, tweetUrl, tweetId, status, totalEntries, validEntries, ... }, winners }',
|
|
339
|
+
summary: 'Get draw details and winners',
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
category: 'extraction',
|
|
343
|
+
free: true,
|
|
344
|
+
method: 'GET',
|
|
345
|
+
parameters: [PARAM_DRAW_ID, PARAM_EXPORT_FORMAT],
|
|
346
|
+
path: '/api/v1/draws/:id/export',
|
|
347
|
+
responseShape: 'CSV, XLSX, or Markdown file download',
|
|
348
|
+
summary: 'Export draw results as CSV, XLSX, or Markdown',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
category: 'extraction',
|
|
352
|
+
free: true,
|
|
353
|
+
method: 'GET',
|
|
354
|
+
parameters: [
|
|
355
|
+
...PAGINATION_PARAMS,
|
|
356
|
+
{ description: 'Filter by tool type', in: 'query', name: 'toolType', required: false, type: 'string' },
|
|
357
|
+
{ description: 'Filter by status (running, completed, failed)', in: 'query', name: 'status', required: false, type: 'string' },
|
|
358
|
+
],
|
|
359
|
+
path: '/api/v1/extractions',
|
|
360
|
+
responseShape: '{ extractions: [{ id, toolType, status, totalResults, createdAt }], hasMore, nextCursor? }',
|
|
361
|
+
summary: 'List extraction jobs with pagination and filters',
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
category: 'extraction',
|
|
365
|
+
free: false,
|
|
366
|
+
method: 'POST',
|
|
367
|
+
parameters: [
|
|
368
|
+
{ description: 'Extraction tool type (reply_extractor, community_extractor, etc.)', in: 'body', name: 'toolType', required: true, type: 'string' },
|
|
369
|
+
{ description: 'Target X username', in: 'body', name: 'targetUsername', required: false, type: 'string' },
|
|
370
|
+
{ description: 'Target tweet ID', in: 'body', name: 'targetTweetId', required: false, type: 'string' },
|
|
371
|
+
{ description: 'Search query for search tools', in: 'body', name: 'searchQuery', required: false, type: 'string' },
|
|
372
|
+
{ description: 'Community ID for community tools', in: 'body', name: 'targetCommunityId', required: false, type: 'string' },
|
|
373
|
+
{ description: 'List ID for list tools', in: 'body', name: 'targetListId', required: false, type: 'string' },
|
|
374
|
+
{ description: 'Space ID for space_explorer', in: 'body', name: 'targetSpaceId', required: false, type: 'string' },
|
|
375
|
+
{ description: 'Max results to return', in: 'body', name: 'resultsLimit', required: false, type: 'number' },
|
|
376
|
+
...EXTRACTION_SEARCH_PARAMS,
|
|
377
|
+
],
|
|
378
|
+
path: '/api/v1/extractions',
|
|
379
|
+
responseShape: '{ id, toolType, status }',
|
|
380
|
+
summary: 'Start a new extraction job',
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
category: 'extraction',
|
|
384
|
+
free: false,
|
|
385
|
+
method: 'POST',
|
|
386
|
+
parameters: [
|
|
387
|
+
{ description: 'Extraction tool type', in: 'body', name: 'toolType', required: true, type: 'string' },
|
|
388
|
+
{ description: 'Target X username', in: 'body', name: 'targetUsername', required: false, type: 'string' },
|
|
389
|
+
{ description: 'Target tweet ID', in: 'body', name: 'targetTweetId', required: false, type: 'string' },
|
|
390
|
+
{ description: 'Search query for search tools', in: 'body', name: 'searchQuery', required: false, type: 'string' },
|
|
391
|
+
{ description: 'Community ID for community tools', in: 'body', name: 'targetCommunityId', required: false, type: 'string' },
|
|
392
|
+
{ description: 'List ID for list tools', in: 'body', name: 'targetListId', required: false, type: 'string' },
|
|
393
|
+
{ description: 'Space ID for space_explorer', in: 'body', name: 'targetSpaceId', required: false, type: 'string' },
|
|
394
|
+
{ description: 'Max results to return', in: 'body', name: 'resultsLimit', required: false, type: 'number' },
|
|
395
|
+
...EXTRACTION_SEARCH_PARAMS,
|
|
396
|
+
],
|
|
397
|
+
path: '/api/v1/extractions/estimate',
|
|
398
|
+
responseShape: '{ estimatedResults?, usagePercent?, projectedPercent?, allowed?, source? }',
|
|
399
|
+
summary: 'Estimate extraction cost before running',
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
category: 'extraction',
|
|
403
|
+
free: true,
|
|
404
|
+
method: 'GET',
|
|
405
|
+
parameters: [
|
|
406
|
+
PARAM_EXTRACTION_ID,
|
|
407
|
+
{ description: 'Max results per page', in: 'query', name: 'limit', required: false, type: 'number' },
|
|
408
|
+
{ description: DESCRIPTION_PAGINATION_CURSOR, in: 'query', name: 'after', required: false, type: 'string' },
|
|
409
|
+
],
|
|
410
|
+
path: '/api/v1/extractions/:id',
|
|
411
|
+
responseShape: '{ job: { id, toolType, status, ... }, results: [...], hasMore, nextCursor? }',
|
|
412
|
+
summary: 'Get extraction job details and results',
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
category: 'extraction',
|
|
416
|
+
free: true,
|
|
417
|
+
method: 'GET',
|
|
418
|
+
parameters: [PARAM_EXTRACTION_ID, PARAM_EXPORT_FORMAT],
|
|
419
|
+
path: '/api/v1/extractions/:id/export',
|
|
420
|
+
responseShape: 'CSV, XLSX, or Markdown file download',
|
|
421
|
+
summary: 'Export extraction results as CSV, XLSX, or Markdown',
|
|
422
|
+
},
|
|
423
|
+
// --- Monitoring ---
|
|
424
|
+
{
|
|
425
|
+
category: 'monitoring',
|
|
426
|
+
free: true,
|
|
427
|
+
method: 'GET',
|
|
428
|
+
path: '/api/v1/monitors',
|
|
429
|
+
responseShape: '{ monitors: [{ id, xUsername, eventTypes, isActive, createdAt }], total }',
|
|
430
|
+
summary: 'List all account monitors',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
category: 'monitoring',
|
|
434
|
+
free: false,
|
|
435
|
+
method: 'POST',
|
|
436
|
+
parameters: [
|
|
437
|
+
{ description: 'X username to monitor without @', in: 'body', name: 'username', required: true, type: 'string' },
|
|
438
|
+
PARAM_EVENT_TYPES_REQUIRED,
|
|
439
|
+
],
|
|
440
|
+
path: '/api/v1/monitors',
|
|
441
|
+
responseShape: '{ id, username, eventTypes, createdAt, xUserId }',
|
|
442
|
+
summary: 'Create a new account monitor',
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
category: 'monitoring',
|
|
446
|
+
free: true,
|
|
447
|
+
method: 'GET',
|
|
448
|
+
parameters: [PARAM_MONITOR_ID],
|
|
449
|
+
path: '/api/v1/monitors/:id',
|
|
450
|
+
responseShape: '{ id, xUsername, eventTypes, isActive, createdAt }',
|
|
451
|
+
summary: 'Get monitor details by ID',
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
category: 'monitoring',
|
|
455
|
+
free: true,
|
|
456
|
+
method: 'PATCH',
|
|
457
|
+
parameters: [
|
|
458
|
+
PARAM_MONITOR_ID,
|
|
459
|
+
{ description: 'Set active or paused', in: 'body', name: 'isActive', required: false, type: 'boolean' },
|
|
460
|
+
PARAM_EVENT_TYPES_OPTIONAL,
|
|
461
|
+
],
|
|
462
|
+
path: '/api/v1/monitors/:id',
|
|
463
|
+
responseShape: '{ id, xUsername, eventTypes, isActive, createdAt }',
|
|
464
|
+
summary: 'Update monitor settings or toggle active state',
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
category: 'monitoring',
|
|
468
|
+
free: true,
|
|
469
|
+
method: 'DELETE',
|
|
470
|
+
parameters: [PARAM_MONITOR_ID],
|
|
471
|
+
path: '/api/v1/monitors/:id',
|
|
472
|
+
responseShape: RESPONSE_SUCCESS,
|
|
473
|
+
summary: 'Delete a monitor and stop tracking',
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
category: 'monitoring',
|
|
477
|
+
free: true,
|
|
478
|
+
method: 'GET',
|
|
479
|
+
path: '/api/v1/monitors/keywords',
|
|
480
|
+
responseShape: '{ monitors: [{ id, query, eventTypes, isActive, createdAt }], total }',
|
|
481
|
+
summary: 'List all keyword monitors',
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
category: 'monitoring',
|
|
485
|
+
free: false,
|
|
486
|
+
method: 'POST',
|
|
487
|
+
parameters: [
|
|
488
|
+
{ description: 'Keyword, phrase, or X search query to monitor', in: 'body', name: 'query', required: true, type: 'string' },
|
|
489
|
+
PARAM_EVENT_TYPES_REQUIRED,
|
|
490
|
+
],
|
|
491
|
+
path: '/api/v1/monitors/keywords',
|
|
492
|
+
responseShape: '{ id, query, eventTypes, isActive, createdAt }',
|
|
493
|
+
summary: 'Create an instant keyword monitor. Active monitors cost 21 credits per hour.',
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
category: 'monitoring',
|
|
497
|
+
free: true,
|
|
498
|
+
method: 'GET',
|
|
499
|
+
parameters: [PARAM_KEYWORD_MONITOR_ID],
|
|
500
|
+
path: '/api/v1/monitors/keywords/:id',
|
|
501
|
+
responseShape: '{ id, query, eventTypes, isActive, createdAt }',
|
|
502
|
+
summary: 'Get keyword monitor details by ID',
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
category: 'monitoring',
|
|
506
|
+
free: true,
|
|
507
|
+
method: 'PATCH',
|
|
508
|
+
parameters: [
|
|
509
|
+
PARAM_KEYWORD_MONITOR_ID,
|
|
510
|
+
{ description: 'Set active or paused', in: 'body', name: 'isActive', required: false, type: 'boolean' },
|
|
511
|
+
PARAM_EVENT_TYPES_OPTIONAL,
|
|
512
|
+
],
|
|
513
|
+
path: '/api/v1/monitors/keywords/:id',
|
|
514
|
+
responseShape: '{ id, query, eventTypes, isActive, createdAt }',
|
|
515
|
+
summary: 'Update keyword monitor settings or toggle active state',
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
category: 'monitoring',
|
|
519
|
+
free: true,
|
|
520
|
+
method: 'DELETE',
|
|
521
|
+
parameters: [PARAM_KEYWORD_MONITOR_ID],
|
|
522
|
+
path: '/api/v1/monitors/keywords/:id',
|
|
523
|
+
responseShape: RESPONSE_SUCCESS,
|
|
524
|
+
summary: 'Delete a keyword monitor and stop tracking',
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
category: 'monitoring',
|
|
528
|
+
free: true,
|
|
529
|
+
method: 'GET',
|
|
530
|
+
parameters: [
|
|
531
|
+
...PAGINATION_PARAMS,
|
|
532
|
+
{ description: 'Filter by monitor ID', in: 'query', name: 'monitorId', required: false, type: 'string' },
|
|
533
|
+
{ description: `Filter by event type: ${DESCRIPTION_EVENT_TYPES}`, in: 'query', name: 'eventType', required: false, type: 'string' },
|
|
534
|
+
],
|
|
535
|
+
path: '/api/v1/events',
|
|
536
|
+
responseShape: '{ events: [{ id, eventType, xUsername, payload, createdAt }], hasMore, nextCursor? }',
|
|
537
|
+
summary: 'List stream events with filters and pagination',
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
category: 'monitoring',
|
|
541
|
+
free: true,
|
|
542
|
+
method: 'GET',
|
|
543
|
+
parameters: [
|
|
544
|
+
{ description: 'Event ID', in: 'path', name: 'id', required: true, type: 'string' },
|
|
545
|
+
],
|
|
546
|
+
path: '/api/v1/events/:id',
|
|
547
|
+
responseShape: '{ id, eventType, xUsername, payload, createdAt, xEventId? }',
|
|
548
|
+
summary: 'Get a single event by ID',
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
category: 'monitoring',
|
|
552
|
+
free: true,
|
|
553
|
+
method: 'GET',
|
|
554
|
+
path: '/api/v1/webhooks',
|
|
555
|
+
responseShape: '{ webhooks: [{ id, url, eventTypes, isActive, createdAt }] }',
|
|
556
|
+
summary: 'List all webhook endpoints',
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
category: 'monitoring',
|
|
560
|
+
free: true,
|
|
561
|
+
method: 'POST',
|
|
562
|
+
parameters: [
|
|
563
|
+
{ description: 'Webhook delivery URL', in: 'body', name: 'url', required: true, type: 'string' },
|
|
564
|
+
PARAM_EVENT_TYPES_REQUIRED,
|
|
565
|
+
],
|
|
566
|
+
path: '/api/v1/webhooks',
|
|
567
|
+
responseShape: '{ id, url, eventTypes, secret, createdAt }',
|
|
568
|
+
summary: 'Create a new webhook endpoint',
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
category: 'monitoring',
|
|
572
|
+
free: true,
|
|
573
|
+
method: 'PATCH',
|
|
574
|
+
parameters: [
|
|
575
|
+
PARAM_WEBHOOK_ID,
|
|
576
|
+
{ description: 'Updated delivery URL', in: 'body', name: 'url', required: false, type: 'string' },
|
|
577
|
+
PARAM_EVENT_TYPES_OPTIONAL,
|
|
578
|
+
{ description: 'Set active or inactive', in: 'body', name: 'isActive', required: false, type: 'boolean' },
|
|
579
|
+
],
|
|
580
|
+
path: '/api/v1/webhooks/:id',
|
|
581
|
+
responseShape: '{ id, url, eventTypes, isActive, createdAt }',
|
|
582
|
+
summary: 'Update webhook URL, events, or active state',
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
category: 'monitoring',
|
|
586
|
+
free: true,
|
|
587
|
+
method: 'DELETE',
|
|
588
|
+
parameters: [PARAM_WEBHOOK_ID],
|
|
589
|
+
path: '/api/v1/webhooks/:id',
|
|
590
|
+
responseShape: RESPONSE_SUCCESS,
|
|
591
|
+
summary: 'Deactivate a webhook endpoint',
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
category: 'monitoring',
|
|
595
|
+
free: true,
|
|
596
|
+
method: 'GET',
|
|
597
|
+
parameters: [PARAM_WEBHOOK_ID],
|
|
598
|
+
path: '/api/v1/webhooks/:id/deliveries',
|
|
599
|
+
responseShape: '{ deliveries: [{ id, status, attempts, statusCode?, createdAt }] }',
|
|
600
|
+
summary: 'List recent deliveries for a webhook',
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
category: 'monitoring',
|
|
604
|
+
free: true,
|
|
605
|
+
method: 'POST',
|
|
606
|
+
parameters: [PARAM_WEBHOOK_ID],
|
|
607
|
+
path: '/api/v1/webhooks/:id/test',
|
|
608
|
+
responseShape: '{ success, statusCode, error? }',
|
|
609
|
+
summary: 'Send a test event to a webhook endpoint',
|
|
610
|
+
},
|
|
611
|
+
// --- Twitter ---
|
|
612
|
+
{
|
|
613
|
+
category: 'twitter',
|
|
614
|
+
free: false,
|
|
615
|
+
method: 'GET',
|
|
616
|
+
parameters: [
|
|
617
|
+
{ description: 'Tweet ID to look up', in: 'path', name: 'tweetId', required: true, type: 'string' },
|
|
618
|
+
],
|
|
619
|
+
mpp: { intent: 'charge', price: MPP_PRICE_CALL },
|
|
620
|
+
path: '/api/v1/x/tweets/:tweetId',
|
|
621
|
+
responseShape: '{ tweet: { id, text, likeCount, retweetCount, replyCount, viewCount, ... }, author? }',
|
|
622
|
+
summary: 'Look up a single tweet with engagement metrics',
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
category: 'twitter',
|
|
626
|
+
free: false,
|
|
627
|
+
method: 'GET',
|
|
628
|
+
parameters: [
|
|
629
|
+
{ description: 'Search query (X search syntax)', in: 'query', name: 'q', required: true, type: 'string' },
|
|
630
|
+
{ description: 'Max tweets to return (default 20, max 200)', in: 'query', name: 'limit', required: false, type: 'number' },
|
|
631
|
+
],
|
|
632
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
633
|
+
path: '/api/v1/x/tweets/search',
|
|
634
|
+
responseShape: '{ tweets: [{ id, text, author?, likeCount?, retweetCount?, media? }], total }',
|
|
635
|
+
summary: 'Search tweets by query with optional limit for pagination',
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
category: 'twitter',
|
|
639
|
+
free: false,
|
|
640
|
+
method: 'GET',
|
|
641
|
+
parameters: [
|
|
642
|
+
{ description: 'X username to look up', in: 'path', name: 'username', required: true, type: 'string' },
|
|
643
|
+
],
|
|
644
|
+
mpp: { intent: 'charge', price: MPP_PRICE_CALL },
|
|
645
|
+
path: '/api/v1/x/users/:username',
|
|
646
|
+
responseShape: '{ id, username, name, followers?, following?, verified?, description? }',
|
|
647
|
+
summary: 'Get X user profile by username',
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
category: 'twitter',
|
|
651
|
+
free: false,
|
|
652
|
+
method: 'GET',
|
|
653
|
+
parameters: [
|
|
654
|
+
{ description: 'Source username', in: 'query', name: 'source', required: true, type: 'string' },
|
|
655
|
+
{ description: 'Target username', in: 'query', name: 'target', required: true, type: 'string' },
|
|
656
|
+
],
|
|
657
|
+
mpp: { intent: 'charge', price: MPP_PRICE_FOLLOW_CHECK },
|
|
658
|
+
path: '/api/v1/x/followers/check',
|
|
659
|
+
responseShape: '{ isFollowing, isFollowedBy, sourceUsername, targetUsername }',
|
|
660
|
+
summary: 'Check follow relationship between two users',
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
category: 'twitter',
|
|
664
|
+
free: false,
|
|
665
|
+
method: 'GET',
|
|
666
|
+
parameters: [
|
|
667
|
+
{ description: 'Tweet ID of the X Article', in: 'path', name: 'tweetId', required: true, type: 'string' },
|
|
668
|
+
],
|
|
669
|
+
mpp: { intent: 'charge', price: MPP_PRICE_FOLLOW_CHECK },
|
|
670
|
+
path: '/api/v1/x/articles/:tweetId',
|
|
671
|
+
responseShape: '{ article: { title, previewText, coverImageUrl, contents, createdAt, likeCount, replyCount, quoteCount, viewCount }, author? }',
|
|
672
|
+
summary: 'Get full content of an X Article (long-form post) by tweet ID',
|
|
673
|
+
},
|
|
674
|
+
// --- Media ---
|
|
675
|
+
{
|
|
676
|
+
category: 'media',
|
|
677
|
+
free: false,
|
|
678
|
+
method: 'POST',
|
|
679
|
+
parameters: [
|
|
680
|
+
{ description: 'Tweet URL or ID (single tweet)', in: 'body', name: 'tweetInput', required: false, type: 'string' },
|
|
681
|
+
{ description: 'Array of tweet URLs or IDs (bulk, max 50)', in: 'body', name: 'tweetIds', required: false, type: 'string[]' },
|
|
682
|
+
],
|
|
683
|
+
mpp: { intent: 'session', price: MPP_PRICE_MEDIA },
|
|
684
|
+
path: '/api/v1/x/media/download',
|
|
685
|
+
responseShape: 'Single: { tweetId, galleryUrl, cacheHit }. Bulk: { galleryUrl, totalTweets, totalMedia }',
|
|
686
|
+
summary: 'Download media from tweets. Single tweetInput or bulk tweetIds. Returns gallery URL.',
|
|
687
|
+
},
|
|
688
|
+
// --- Twitter (Trends) ---
|
|
689
|
+
{
|
|
690
|
+
category: 'twitter',
|
|
691
|
+
free: false,
|
|
692
|
+
method: 'GET',
|
|
693
|
+
parameters: [
|
|
694
|
+
{ description: 'WOEID location ID (1 for worldwide)', in: 'query', name: 'woeid', required: false, type: 'number' },
|
|
695
|
+
{ description: 'Max number of trends', in: 'query', name: 'count', required: false, type: 'number' },
|
|
696
|
+
],
|
|
697
|
+
mpp: { intent: 'charge', price: MPP_PRICE_TREND },
|
|
698
|
+
path: '/api/v1/trends',
|
|
699
|
+
responseShape: '{ trends: [{ name, query?, description?, rank? }], total, woeid }',
|
|
700
|
+
summary: 'Get current trending topics on X',
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
category: 'twitter',
|
|
704
|
+
free: false,
|
|
705
|
+
method: 'GET',
|
|
706
|
+
parameters: [
|
|
707
|
+
{ description: 'WOEID location ID (1 for worldwide)', in: 'query', name: 'woeid', required: false, type: 'number' },
|
|
708
|
+
{ description: 'Max number of trends', in: 'query', name: 'count', required: false, type: 'number' },
|
|
709
|
+
],
|
|
710
|
+
mpp: { intent: 'charge', price: MPP_PRICE_TREND },
|
|
711
|
+
path: '/api/v1/x/trends',
|
|
712
|
+
responseShape: '{ trends: [{ name, query?, description?, rank? }], count, woeid }',
|
|
713
|
+
summary: 'Get X trending topics by region',
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
category: 'twitter',
|
|
717
|
+
free: false,
|
|
718
|
+
method: 'GET',
|
|
719
|
+
parameters: [PARAM_TWEET_ID, PARAM_CURSOR],
|
|
720
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
721
|
+
path: '/api/v1/x/tweets/:id/favoriters',
|
|
722
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
723
|
+
summary: 'Get users who liked a tweet. Returns about 20 per page.',
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
category: 'twitter',
|
|
727
|
+
free: false,
|
|
728
|
+
method: 'GET',
|
|
729
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR],
|
|
730
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
731
|
+
path: '/api/v1/x/users/:id/likes',
|
|
732
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
733
|
+
summary: 'Get tweets liked by a user. Returns about 20 per page.',
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
category: 'twitter',
|
|
737
|
+
free: false,
|
|
738
|
+
method: 'GET',
|
|
739
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR],
|
|
740
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
741
|
+
path: '/api/v1/x/users/:id/media',
|
|
742
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
743
|
+
summary: 'Get media tweets by a user. Returns about 20 per page.',
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
category: 'twitter',
|
|
747
|
+
free: false,
|
|
748
|
+
method: 'GET',
|
|
749
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR],
|
|
750
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
751
|
+
path: '/api/v1/x/users/:id/followers-you-know',
|
|
752
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
753
|
+
summary: 'Get followers you know for a user. Returns about 20 per page.',
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
category: 'twitter',
|
|
757
|
+
free: false,
|
|
758
|
+
method: 'GET',
|
|
759
|
+
parameters: [
|
|
760
|
+
{ description: 'Optional bookmark folder ID', in: 'query', name: 'folderId', required: false, type: 'string' },
|
|
761
|
+
PARAM_CURSOR,
|
|
762
|
+
],
|
|
763
|
+
path: '/api/v1/x/bookmarks',
|
|
764
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
765
|
+
sensitive: true,
|
|
766
|
+
summary: 'Get bookmarked tweets. Requires explicit user request.',
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
category: 'twitter',
|
|
770
|
+
free: false,
|
|
771
|
+
method: 'GET',
|
|
772
|
+
parameters: [PARAM_CURSOR],
|
|
773
|
+
path: '/api/v1/x/bookmarks/folders',
|
|
774
|
+
responseShape: '{ folders: [{ id, name }], has_more, next_cursor }',
|
|
775
|
+
sensitive: true,
|
|
776
|
+
summary: 'Get bookmark folders. Requires explicit user request.',
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
category: 'twitter',
|
|
780
|
+
free: false,
|
|
781
|
+
method: 'GET',
|
|
782
|
+
parameters: [
|
|
783
|
+
{ description: 'Notification type filter: All, Verified, Mentions', in: 'query', name: 'type', required: false, type: 'string' },
|
|
784
|
+
PARAM_CURSOR,
|
|
785
|
+
],
|
|
786
|
+
path: '/api/v1/x/notifications',
|
|
787
|
+
responseShape: '{ notifications: [{ id, type?, message?, timestamp? }], has_more, next_cursor }',
|
|
788
|
+
sensitive: true,
|
|
789
|
+
summary: 'Get notifications. Requires explicit user request.',
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
category: 'twitter',
|
|
793
|
+
free: false,
|
|
794
|
+
method: 'GET',
|
|
795
|
+
parameters: [
|
|
796
|
+
{ description: 'Comma-separated tweet IDs to exclude from results', in: 'query', name: 'seenTweetIds', required: false, type: 'string' },
|
|
797
|
+
PARAM_CURSOR,
|
|
798
|
+
],
|
|
799
|
+
path: '/api/v1/x/timeline',
|
|
800
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
801
|
+
sensitive: true,
|
|
802
|
+
summary: 'Get home timeline. Requires explicit user request.',
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
category: 'twitter',
|
|
806
|
+
free: false,
|
|
807
|
+
method: 'GET',
|
|
808
|
+
parameters: [
|
|
809
|
+
{ description: 'Target user ID', in: 'path', name: 'userId', required: true, type: 'string' },
|
|
810
|
+
{ description: 'Connected X account username without @', in: 'query', name: 'account', required: true, type: 'string' },
|
|
811
|
+
PARAM_CURSOR,
|
|
812
|
+
],
|
|
813
|
+
path: '/api/v1/x/dm/:userId/history',
|
|
814
|
+
responseShape: '{ messages: [{ id, text?, sender_id?, receiver_id?, created?, media_url? }], has_more, next_cursor }',
|
|
815
|
+
sensitive: true,
|
|
816
|
+
summary: 'Get DM conversation history. Requires explicit user request.',
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
category: 'twitter',
|
|
820
|
+
free: false,
|
|
821
|
+
method: 'GET',
|
|
822
|
+
parameters: [
|
|
823
|
+
PARAM_USER_ID,
|
|
824
|
+
PARAM_CURSOR,
|
|
825
|
+
{ description: 'Include replies (default false)', in: 'query', name: 'includeReplies', required: false, type: 'boolean' },
|
|
826
|
+
{ description: 'Include parent tweet for replies (default false)', in: 'query', name: 'includeParentTweet', required: false, type: 'boolean' },
|
|
827
|
+
],
|
|
828
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
829
|
+
path: '/api/v1/x/users/:id/tweets',
|
|
830
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
831
|
+
summary: 'Get latest tweets by a user. Preferred over search for user timelines.',
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
category: 'twitter',
|
|
835
|
+
free: false,
|
|
836
|
+
method: 'GET',
|
|
837
|
+
parameters: [PARAM_COMMUNITY_ID],
|
|
838
|
+
mpp: { intent: 'charge', price: MPP_PRICE_CALL },
|
|
839
|
+
path: '/api/v1/x/communities/:id/info',
|
|
840
|
+
responseShape: '{ community: { id, name?, description?, member_count?, moderator_count?, created?, banner_url?, join_policy?, rules? } }',
|
|
841
|
+
summary: 'Get community details.',
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
category: 'twitter',
|
|
845
|
+
free: false,
|
|
846
|
+
method: 'GET',
|
|
847
|
+
parameters: [PARAM_COMMUNITY_ID, PARAM_CURSOR, PARAM_PAGE_SIZE_20],
|
|
848
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
849
|
+
path: '/api/v1/x/communities/:id/members',
|
|
850
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
851
|
+
summary: 'Get community members. Use cursor for pagination.',
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
category: 'twitter',
|
|
855
|
+
free: false,
|
|
856
|
+
method: 'GET',
|
|
857
|
+
parameters: [PARAM_COMMUNITY_ID, PARAM_CURSOR],
|
|
858
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
859
|
+
path: '/api/v1/x/communities/:id/moderators',
|
|
860
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
861
|
+
summary: 'Get community moderators. Returns about 20 per page.',
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
category: 'twitter',
|
|
865
|
+
free: false,
|
|
866
|
+
method: 'GET',
|
|
867
|
+
parameters: [PARAM_COMMUNITY_ID, PARAM_CURSOR],
|
|
868
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
869
|
+
path: '/api/v1/x/communities/:id/tweets',
|
|
870
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
871
|
+
summary: 'Get community tweets. Returns about 20 per page.',
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
category: 'twitter',
|
|
875
|
+
free: false,
|
|
876
|
+
method: 'GET',
|
|
877
|
+
parameters: [PARAM_SEARCH_QUERY, PARAM_QUERY_TYPE, PARAM_CURSOR],
|
|
878
|
+
mpp: { intent: 'session', price: MPP_PRICE_COMMUNITY },
|
|
879
|
+
path: '/api/v1/x/communities/search',
|
|
880
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
881
|
+
summary: 'Search tweets across all communities.',
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
category: 'twitter',
|
|
885
|
+
free: false,
|
|
886
|
+
method: 'GET',
|
|
887
|
+
parameters: [PARAM_SEARCH_QUERY, PARAM_QUERY_TYPE, PARAM_CURSOR],
|
|
888
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
889
|
+
path: '/api/v1/x/communities/tweets',
|
|
890
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
891
|
+
summary: 'Get tweets from all communities matching a query.',
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
category: 'twitter',
|
|
895
|
+
free: false,
|
|
896
|
+
method: 'GET',
|
|
897
|
+
parameters: [PARAM_LIST_ID, PARAM_CURSOR],
|
|
898
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
899
|
+
path: '/api/v1/x/lists/:id/followers',
|
|
900
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
901
|
+
summary: 'Get list followers.',
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
category: 'twitter',
|
|
905
|
+
free: false,
|
|
906
|
+
method: 'GET',
|
|
907
|
+
parameters: [PARAM_LIST_ID, PARAM_CURSOR, PARAM_PAGE_SIZE_20],
|
|
908
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
909
|
+
path: '/api/v1/x/lists/:id/members',
|
|
910
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
911
|
+
summary: 'Get list members.',
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
category: 'twitter',
|
|
915
|
+
free: false,
|
|
916
|
+
method: 'GET',
|
|
917
|
+
parameters: [
|
|
918
|
+
PARAM_LIST_ID,
|
|
919
|
+
PARAM_CURSOR,
|
|
920
|
+
PARAM_SINCE_TIME,
|
|
921
|
+
PARAM_UNTIL_TIME,
|
|
922
|
+
{ description: 'Include replies (default false)', in: 'query', name: 'includeReplies', required: false, type: 'boolean' },
|
|
923
|
+
],
|
|
924
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
925
|
+
path: '/api/v1/x/lists/:id/tweets',
|
|
926
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
927
|
+
summary: 'Get list tweets. Returns about 20 per page.',
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
category: 'twitter',
|
|
931
|
+
free: false,
|
|
932
|
+
method: 'GET',
|
|
933
|
+
parameters: [
|
|
934
|
+
{ description: 'Comma-separated tweet IDs (max 100)', in: 'query', name: 'ids', required: true, type: 'string' },
|
|
935
|
+
],
|
|
936
|
+
path: '/api/v1/x/tweets',
|
|
937
|
+
responseShape: `{ tweets: [${RESPONSE_TWEET_BASIC}], has_more: false, next_cursor: "" }`,
|
|
938
|
+
summary: 'Get multiple tweets by IDs. Max 100 IDs per request.',
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
category: 'twitter',
|
|
942
|
+
free: false,
|
|
943
|
+
method: 'GET',
|
|
944
|
+
parameters: [
|
|
945
|
+
PARAM_TWEET_ID,
|
|
946
|
+
PARAM_CURSOR,
|
|
947
|
+
PARAM_SINCE_TIME,
|
|
948
|
+
PARAM_UNTIL_TIME,
|
|
949
|
+
{ description: 'Include replies (default true)', in: 'query', name: 'includeReplies', required: false, type: 'boolean' },
|
|
950
|
+
],
|
|
951
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
952
|
+
path: '/api/v1/x/tweets/:id/quotes',
|
|
953
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
954
|
+
summary: 'Get quote tweets of a tweet.',
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
category: 'twitter',
|
|
958
|
+
free: false,
|
|
959
|
+
method: 'GET',
|
|
960
|
+
parameters: [PARAM_TWEET_ID, PARAM_CURSOR, PARAM_SINCE_TIME, PARAM_UNTIL_TIME],
|
|
961
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
962
|
+
path: '/api/v1/x/tweets/:id/replies',
|
|
963
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
964
|
+
summary: 'Get replies to a tweet.',
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
category: 'twitter',
|
|
968
|
+
free: false,
|
|
969
|
+
method: 'GET',
|
|
970
|
+
parameters: [PARAM_TWEET_ID, PARAM_CURSOR],
|
|
971
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
972
|
+
path: '/api/v1/x/tweets/:id/retweeters',
|
|
973
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
974
|
+
summary: 'Get users who retweeted a tweet.',
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
category: 'twitter',
|
|
978
|
+
free: false,
|
|
979
|
+
method: 'GET',
|
|
980
|
+
parameters: [PARAM_TWEET_ID, PARAM_CURSOR],
|
|
981
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
982
|
+
path: '/api/v1/x/tweets/:id/thread',
|
|
983
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
984
|
+
summary: 'Get thread context for a tweet.',
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
category: 'twitter',
|
|
988
|
+
free: false,
|
|
989
|
+
method: 'GET',
|
|
990
|
+
parameters: [
|
|
991
|
+
{ description: 'Comma-separated user IDs (max 100)', in: 'query', name: 'ids', required: true, type: 'string' },
|
|
992
|
+
],
|
|
993
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
994
|
+
path: '/api/v1/x/users/batch',
|
|
995
|
+
responseShape: `{ users: [${RESPONSE_USER}] }`,
|
|
996
|
+
summary: 'Get multiple users by IDs. Max 100 IDs per request.',
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
category: 'twitter',
|
|
1000
|
+
free: false,
|
|
1001
|
+
method: 'GET',
|
|
1002
|
+
parameters: [PARAM_SEARCH_QUERY, PARAM_CURSOR],
|
|
1003
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
1004
|
+
path: '/api/v1/x/users/search',
|
|
1005
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
1006
|
+
summary: 'Search users by name or username.',
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
category: 'twitter',
|
|
1010
|
+
free: false,
|
|
1011
|
+
method: 'GET',
|
|
1012
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR, PARAM_AFTER_ALIAS, PARAM_PAGE_SIZE_200, PARAM_LIMIT_ALIAS],
|
|
1013
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
1014
|
+
path: '/api/v1/x/users/:id/followers',
|
|
1015
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
1016
|
+
summary: 'Get user followers. Use cursor for pagination.',
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
category: 'twitter',
|
|
1020
|
+
free: false,
|
|
1021
|
+
method: 'GET',
|
|
1022
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR, PARAM_AFTER_ALIAS, PARAM_PAGE_SIZE_200, PARAM_LIMIT_ALIAS],
|
|
1023
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
1024
|
+
path: '/api/v1/x/users/:id/following',
|
|
1025
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
1026
|
+
summary: 'Get users this user follows. Use cursor for pagination.',
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
category: 'twitter',
|
|
1030
|
+
free: false,
|
|
1031
|
+
method: 'GET',
|
|
1032
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR, PARAM_SINCE_TIME, PARAM_UNTIL_TIME],
|
|
1033
|
+
mpp: { intent: 'session', price: MPP_PRICE_TWEET },
|
|
1034
|
+
path: '/api/v1/x/users/:id/mentions',
|
|
1035
|
+
responseShape: RESPONSE_TWEETS_PAGINATED,
|
|
1036
|
+
summary: 'Get tweets mentioning a user.',
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
category: 'twitter',
|
|
1040
|
+
free: false,
|
|
1041
|
+
method: 'GET',
|
|
1042
|
+
parameters: [PARAM_USER_ID, PARAM_CURSOR],
|
|
1043
|
+
mpp: { intent: 'session', price: MPP_PRICE_USER },
|
|
1044
|
+
path: '/api/v1/x/users/:id/verified-followers',
|
|
1045
|
+
responseShape: RESPONSE_USERS_PAGINATED,
|
|
1046
|
+
summary: 'Get verified followers.',
|
|
1047
|
+
},
|
|
1048
|
+
// --- X Account Management ---
|
|
1049
|
+
{
|
|
1050
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1051
|
+
free: true,
|
|
1052
|
+
method: 'GET',
|
|
1053
|
+
path: '/api/v1/x/accounts',
|
|
1054
|
+
responseShape: '{ accounts: [{ id, xUserId, xUsername, status, createdAt }] }',
|
|
1055
|
+
summary: 'List connected X accounts',
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
agentProhibited: true,
|
|
1059
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1060
|
+
free: true,
|
|
1061
|
+
method: 'POST',
|
|
1062
|
+
parameters: [
|
|
1063
|
+
{ description: 'X username', in: 'body', name: 'username', required: true, type: 'string' },
|
|
1064
|
+
{ description: 'Account email', in: 'body', name: 'email', required: true, type: 'string' },
|
|
1065
|
+
{ description: 'Account password', in: 'body', name: 'password', required: true, type: 'string' },
|
|
1066
|
+
{ description: 'TOTP secret for 2FA', in: 'body', name: 'totp_secret', required: false, type: 'string' },
|
|
1067
|
+
],
|
|
1068
|
+
path: '/api/v1/x/accounts',
|
|
1069
|
+
responseShape: '{ id, xUserId, xUsername, status }',
|
|
1070
|
+
summary: 'Connect X account (dashboard only - agent-prohibited)',
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
agentProhibited: true,
|
|
1074
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1075
|
+
free: true,
|
|
1076
|
+
method: 'GET',
|
|
1077
|
+
parameters: [PARAM_X_ACCOUNT_ID],
|
|
1078
|
+
path: '/api/v1/x/accounts/:id',
|
|
1079
|
+
responseShape: '{ id, xUserId, xUsername, status, cookiesObtainedAt, createdAt }',
|
|
1080
|
+
summary: 'Get X account details',
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
agentProhibited: true,
|
|
1084
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1085
|
+
free: true,
|
|
1086
|
+
method: 'DELETE',
|
|
1087
|
+
parameters: [PARAM_X_ACCOUNT_ID],
|
|
1088
|
+
path: '/api/v1/x/accounts/:id',
|
|
1089
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1090
|
+
summary: 'Disconnect X account',
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
agentProhibited: true,
|
|
1094
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1095
|
+
free: true,
|
|
1096
|
+
method: 'POST',
|
|
1097
|
+
parameters: [
|
|
1098
|
+
PARAM_X_ACCOUNT_ID,
|
|
1099
|
+
{ description: 'Account password', in: 'body', name: 'password', required: true, type: 'string' },
|
|
1100
|
+
{ description: 'TOTP secret for 2FA', in: 'body', name: 'totp_secret', required: false, type: 'string' },
|
|
1101
|
+
],
|
|
1102
|
+
path: '/api/v1/x/accounts/:id/reauth',
|
|
1103
|
+
responseShape: '{ id, xUsername, status }',
|
|
1104
|
+
summary: 'Re-authenticate X account (dashboard only - agent-prohibited)',
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
agentProhibited: true,
|
|
1108
|
+
category: CATEGORY_X_ACCOUNTS,
|
|
1109
|
+
free: true,
|
|
1110
|
+
method: 'POST',
|
|
1111
|
+
path: '/api/v1/x/accounts/bulk-retry',
|
|
1112
|
+
responseShape: '{ cleared }',
|
|
1113
|
+
summary: 'Bulk retry temporarily failed X accounts (dashboard only - agent-prohibited)',
|
|
1114
|
+
},
|
|
1115
|
+
// --- X Write Actions ---
|
|
1116
|
+
{
|
|
1117
|
+
category: CATEGORY_X_WRITE,
|
|
1118
|
+
free: false,
|
|
1119
|
+
method: 'POST',
|
|
1120
|
+
parameters: [
|
|
1121
|
+
PARAM_X_ACCOUNT,
|
|
1122
|
+
{ description: 'Tweet text', in: 'body', name: 'text', required: true, type: 'string' },
|
|
1123
|
+
{ description: 'Tweet ID to reply to', in: 'body', name: 'reply_to_tweet_id', required: false, type: 'string' },
|
|
1124
|
+
{ description: 'URL to attach', in: 'body', name: 'attachment_url', required: false, type: 'string' },
|
|
1125
|
+
{ description: 'Community ID to post in', in: 'body', name: 'community_id', required: false, type: 'string' },
|
|
1126
|
+
{ description: 'Whether this is a long-form note tweet', in: 'body', name: 'is_note_tweet', required: false, type: 'boolean' },
|
|
1127
|
+
{ description: 'Array of media IDs to attach', in: 'body', name: 'media_ids', required: false, type: 'array' },
|
|
1128
|
+
],
|
|
1129
|
+
path: '/api/v1/x/tweets',
|
|
1130
|
+
responseShape: '{ tweetId, success: true }',
|
|
1131
|
+
summary: 'Create tweet',
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
category: CATEGORY_X_WRITE,
|
|
1135
|
+
free: false,
|
|
1136
|
+
method: 'DELETE',
|
|
1137
|
+
parameters: PARAMS_TWEET_ACTION,
|
|
1138
|
+
path: '/api/v1/x/tweets/:id',
|
|
1139
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1140
|
+
summary: 'Delete tweet',
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
category: CATEGORY_X_WRITE,
|
|
1144
|
+
free: false,
|
|
1145
|
+
method: 'POST',
|
|
1146
|
+
parameters: PARAMS_TWEET_ACTION,
|
|
1147
|
+
path: '/api/v1/x/tweets/:id/like',
|
|
1148
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1149
|
+
summary: 'Like tweet',
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
category: CATEGORY_X_WRITE,
|
|
1153
|
+
free: false,
|
|
1154
|
+
method: 'DELETE',
|
|
1155
|
+
parameters: PARAMS_TWEET_ACTION,
|
|
1156
|
+
path: '/api/v1/x/tweets/:id/like',
|
|
1157
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1158
|
+
summary: 'Unlike tweet',
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
category: CATEGORY_X_WRITE,
|
|
1162
|
+
free: false,
|
|
1163
|
+
method: 'POST',
|
|
1164
|
+
parameters: PARAMS_TWEET_ACTION,
|
|
1165
|
+
path: '/api/v1/x/tweets/:id/retweet',
|
|
1166
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1167
|
+
summary: 'Retweet',
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
category: CATEGORY_X_WRITE,
|
|
1171
|
+
free: false,
|
|
1172
|
+
method: 'DELETE',
|
|
1173
|
+
parameters: PARAMS_TWEET_ACTION,
|
|
1174
|
+
path: '/api/v1/x/tweets/:id/retweet',
|
|
1175
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1176
|
+
summary: 'Unretweet',
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
category: CATEGORY_X_WRITE,
|
|
1180
|
+
free: false,
|
|
1181
|
+
method: 'POST',
|
|
1182
|
+
parameters: [PARAM_USER_ID_FOLLOW, PARAM_X_ACCOUNT],
|
|
1183
|
+
path: '/api/v1/x/users/:id/follow',
|
|
1184
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1185
|
+
summary: 'Follow user',
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
category: CATEGORY_X_WRITE,
|
|
1189
|
+
free: false,
|
|
1190
|
+
method: 'DELETE',
|
|
1191
|
+
parameters: [PARAM_USER_ID_UNFOLLOW, PARAM_X_ACCOUNT],
|
|
1192
|
+
path: '/api/v1/x/users/:id/follow',
|
|
1193
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1194
|
+
summary: 'Unfollow user',
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
category: CATEGORY_X_WRITE,
|
|
1198
|
+
free: false,
|
|
1199
|
+
method: 'POST',
|
|
1200
|
+
parameters: [PARAM_USER_ID_REMOVE_FOLLOWER, PARAM_X_ACCOUNT],
|
|
1201
|
+
path: '/api/v1/x/users/:id/remove-follower',
|
|
1202
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1203
|
+
summary: 'Remove follower',
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
category: CATEGORY_X_WRITE,
|
|
1207
|
+
free: false,
|
|
1208
|
+
method: 'POST',
|
|
1209
|
+
parameters: [
|
|
1210
|
+
{ description: 'Recipient user ID', in: 'path', name: 'userId', required: true, type: 'string' },
|
|
1211
|
+
PARAM_X_ACCOUNT,
|
|
1212
|
+
{ description: 'Message text', in: 'body', name: 'text', required: true, type: 'string' },
|
|
1213
|
+
{ description: 'Array of media IDs to attach', in: 'body', name: 'media_ids', required: false, type: 'array' },
|
|
1214
|
+
{ description: 'Message ID to reply to', in: 'body', name: 'reply_to_message_id', required: false, type: 'string' },
|
|
1215
|
+
],
|
|
1216
|
+
path: '/api/v1/x/dm/:userId',
|
|
1217
|
+
responseShape: '{ messageId, success: true }',
|
|
1218
|
+
summary: 'Send DM',
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
category: CATEGORY_X_WRITE,
|
|
1222
|
+
free: false,
|
|
1223
|
+
method: 'POST',
|
|
1224
|
+
parameters: [
|
|
1225
|
+
PARAM_X_ACCOUNT,
|
|
1226
|
+
{ description: 'Media file to upload', in: 'body', name: 'file', required: false, type: 'binary' },
|
|
1227
|
+
PARAM_MEDIA_URL,
|
|
1228
|
+
{ description: 'Whether this is a long video', in: 'body', name: 'is_long_video', required: false, type: 'boolean' },
|
|
1229
|
+
],
|
|
1230
|
+
path: '/api/v1/x/media',
|
|
1231
|
+
responseShape: '{ mediaId, success: true }',
|
|
1232
|
+
summary: 'Upload media',
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
category: CATEGORY_X_WRITE,
|
|
1236
|
+
free: false,
|
|
1237
|
+
method: 'PATCH',
|
|
1238
|
+
parameters: [
|
|
1239
|
+
PARAM_X_ACCOUNT,
|
|
1240
|
+
{ description: 'Display name', in: 'body', name: 'name', required: false, type: 'string' },
|
|
1241
|
+
{ description: 'Bio description', in: 'body', name: 'description', required: false, type: 'string' },
|
|
1242
|
+
{ description: 'Location', in: 'body', name: 'location', required: false, type: 'string' },
|
|
1243
|
+
{ description: 'Website URL', in: 'body', name: 'url', required: false, type: 'string' },
|
|
1244
|
+
],
|
|
1245
|
+
path: '/api/v1/x/profile',
|
|
1246
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1247
|
+
summary: 'Update profile',
|
|
1248
|
+
},
|
|
1249
|
+
{
|
|
1250
|
+
category: CATEGORY_X_WRITE,
|
|
1251
|
+
free: false,
|
|
1252
|
+
method: 'PATCH',
|
|
1253
|
+
parameters: [
|
|
1254
|
+
PARAM_X_ACCOUNT,
|
|
1255
|
+
{ description: 'Avatar image file', in: 'body', name: 'file', required: false, type: 'binary' },
|
|
1256
|
+
PARAM_MEDIA_URL,
|
|
1257
|
+
],
|
|
1258
|
+
path: '/api/v1/x/profile/avatar',
|
|
1259
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1260
|
+
summary: 'Update avatar',
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
category: CATEGORY_X_WRITE,
|
|
1264
|
+
free: false,
|
|
1265
|
+
method: 'PATCH',
|
|
1266
|
+
parameters: [
|
|
1267
|
+
PARAM_X_ACCOUNT,
|
|
1268
|
+
{ description: 'Banner image file', in: 'body', name: 'file', required: false, type: 'binary' },
|
|
1269
|
+
PARAM_MEDIA_URL,
|
|
1270
|
+
],
|
|
1271
|
+
path: '/api/v1/x/profile/banner',
|
|
1272
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1273
|
+
summary: 'Update banner',
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
category: CATEGORY_X_WRITE,
|
|
1277
|
+
free: false,
|
|
1278
|
+
method: 'POST',
|
|
1279
|
+
parameters: [
|
|
1280
|
+
PARAM_X_ACCOUNT,
|
|
1281
|
+
{ description: 'Community name', in: 'body', name: 'name', required: true, type: 'string' },
|
|
1282
|
+
{ description: 'Community description', in: 'body', name: 'description', required: false, type: 'string' },
|
|
1283
|
+
],
|
|
1284
|
+
path: '/api/v1/x/communities',
|
|
1285
|
+
responseShape: '{ communityId, success: true }',
|
|
1286
|
+
summary: 'Create community',
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
category: CATEGORY_X_WRITE,
|
|
1290
|
+
free: false,
|
|
1291
|
+
method: 'DELETE',
|
|
1292
|
+
parameters: [
|
|
1293
|
+
PARAM_COMMUNITY_ID,
|
|
1294
|
+
PARAM_X_ACCOUNT,
|
|
1295
|
+
{ description: 'Community name for confirmation', in: 'body', name: 'community_name', required: true, type: 'string' },
|
|
1296
|
+
],
|
|
1297
|
+
path: '/api/v1/x/communities/:id',
|
|
1298
|
+
responseShape: RESPONSE_SUCCESS,
|
|
1299
|
+
summary: 'Delete community',
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
category: CATEGORY_X_WRITE,
|
|
1303
|
+
free: false,
|
|
1304
|
+
method: 'POST',
|
|
1305
|
+
parameters: PARAMS_COMMUNITY_ACTION,
|
|
1306
|
+
path: '/api/v1/x/communities/:id/join',
|
|
1307
|
+
responseShape: RESPONSE_COMMUNITY_ACTION,
|
|
1308
|
+
summary: 'Join community',
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
category: CATEGORY_X_WRITE,
|
|
1312
|
+
free: false,
|
|
1313
|
+
method: 'DELETE',
|
|
1314
|
+
parameters: PARAMS_COMMUNITY_ACTION,
|
|
1315
|
+
path: '/api/v1/x/communities/:id/join',
|
|
1316
|
+
responseShape: RESPONSE_COMMUNITY_ACTION,
|
|
1317
|
+
summary: 'Leave community',
|
|
1318
|
+
},
|
|
1319
|
+
// --- Support ---
|
|
1320
|
+
{
|
|
1321
|
+
agentProhibited: true,
|
|
1322
|
+
category: CATEGORY_SUPPORT,
|
|
1323
|
+
free: true,
|
|
1324
|
+
method: 'POST',
|
|
1325
|
+
parameters: [
|
|
1326
|
+
{ description: 'Ticket subject (1-500 chars)', in: 'body', name: 'subject', required: true, type: 'string' },
|
|
1327
|
+
{ description: 'Initial message (1-10000 chars)', in: 'body', name: 'body', required: true, type: 'string' },
|
|
1328
|
+
],
|
|
1329
|
+
path: '/api/v1/support/tickets',
|
|
1330
|
+
responseShape: '{ publicId }',
|
|
1331
|
+
summary: 'Open a new support ticket',
|
|
1332
|
+
},
|
|
1333
|
+
{
|
|
1334
|
+
agentProhibited: true,
|
|
1335
|
+
category: CATEGORY_SUPPORT,
|
|
1336
|
+
free: true,
|
|
1337
|
+
method: 'GET',
|
|
1338
|
+
path: '/api/v1/support/tickets',
|
|
1339
|
+
responseShape: '{ tickets: [{ publicId, subject, status, messageCount, createdAt, updatedAt }] }',
|
|
1340
|
+
summary: 'List your support tickets',
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
agentProhibited: true,
|
|
1344
|
+
category: CATEGORY_SUPPORT,
|
|
1345
|
+
free: true,
|
|
1346
|
+
method: 'GET',
|
|
1347
|
+
parameters: [PARAM_TICKET_ID],
|
|
1348
|
+
path: '/api/v1/support/tickets/:id',
|
|
1349
|
+
responseShape: '{ publicId, subject, status, messages: [{ body, sender, createdAt }], createdAt, updatedAt }',
|
|
1350
|
+
summary: 'Get a ticket with message history',
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
agentProhibited: true,
|
|
1354
|
+
category: CATEGORY_SUPPORT,
|
|
1355
|
+
free: true,
|
|
1356
|
+
method: 'PATCH',
|
|
1357
|
+
parameters: [
|
|
1358
|
+
PARAM_TICKET_ID,
|
|
1359
|
+
{ description: 'New status: open, resolved, closed', in: 'body', name: 'status', required: true, type: 'string' },
|
|
1360
|
+
],
|
|
1361
|
+
path: '/api/v1/support/tickets/:id',
|
|
1362
|
+
responseShape: '{ publicId, status }',
|
|
1363
|
+
summary: 'Update ticket status',
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
agentProhibited: true,
|
|
1367
|
+
category: CATEGORY_SUPPORT,
|
|
1368
|
+
free: true,
|
|
1369
|
+
method: 'POST',
|
|
1370
|
+
parameters: [
|
|
1371
|
+
PARAM_TICKET_ID,
|
|
1372
|
+
{ description: 'Message content (1-10000 chars)', in: 'body', name: 'body', required: true, type: 'string' },
|
|
1373
|
+
],
|
|
1374
|
+
path: '/api/v1/support/tickets/:id/messages',
|
|
1375
|
+
responseShape: '{ publicId }',
|
|
1376
|
+
summary: 'Reply to a support ticket',
|
|
1377
|
+
},
|
|
1378
|
+
// --- Credits ---
|
|
1379
|
+
// Balance reads stay agent-callable. Checkout and saved-card charge
|
|
1380
|
+
// endpoints remain documented but are dashboard-only for agent safety.
|
|
1381
|
+
{
|
|
1382
|
+
category: 'credits',
|
|
1383
|
+
free: true,
|
|
1384
|
+
method: 'GET',
|
|
1385
|
+
path: '/api/v1/credits',
|
|
1386
|
+
responseShape: '{ auto_topup_enabled: boolean, balance: number, lifetime_purchased: number, lifetime_used: number }',
|
|
1387
|
+
summary: 'Get credits balance',
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
agentProhibited: true,
|
|
1391
|
+
category: 'credits',
|
|
1392
|
+
free: true,
|
|
1393
|
+
method: 'POST',
|
|
1394
|
+
parameters: [
|
|
1395
|
+
{ description: 'Amount in USD to top up ($10 minimum)', in: 'body', name: 'dollars', required: true, type: 'number' },
|
|
1396
|
+
],
|
|
1397
|
+
path: '/api/v1/credits/topup',
|
|
1398
|
+
responseShape: '{ url: string }',
|
|
1399
|
+
summary: 'Top up credits via Stripe Checkout. $10 min.',
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
agentProhibited: true,
|
|
1403
|
+
category: 'credits',
|
|
1404
|
+
free: true,
|
|
1405
|
+
method: 'GET',
|
|
1406
|
+
parameters: [
|
|
1407
|
+
{ description: 'Stripe Checkout session ID returned from credit top-up checkout', in: 'query', name: 'session_id', required: true, type: 'string' },
|
|
1408
|
+
],
|
|
1409
|
+
path: '/api/v1/credits/topup/status',
|
|
1410
|
+
responseShape: '{ status: "paid" | "open" | "expired" | "unknown", amount_dollars?: number, credits?: number }',
|
|
1411
|
+
summary: 'Check credit top-up checkout status.',
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
agentProhibited: true,
|
|
1415
|
+
category: 'credits',
|
|
1416
|
+
free: true,
|
|
1417
|
+
method: 'POST',
|
|
1418
|
+
parameters: [
|
|
1419
|
+
{ description: 'Amount in USD to charge saved card ($10 minimum, $500 maximum)', in: 'body', name: 'dollars', required: true, type: 'number' },
|
|
1420
|
+
],
|
|
1421
|
+
path: '/api/v1/credits/quick-topup',
|
|
1422
|
+
responseShape: '{ outcome: "charged", credits: number, balance: number } | { outcome: "no_payment_method" } | { outcome: "requires_action", clientSecret: string }',
|
|
1423
|
+
summary: 'Instantly charge saved card for credits. Falls back to checkout redirect if no payment method.',
|
|
1424
|
+
},
|
|
1425
|
+
];
|
|
1426
|
+
export { API_SPEC };
|
|
1427
|
+
//# sourceMappingURL=api-spec.js.map
|