@xquik/tweetclaw 1.0.3 → 1.2.0

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 CHANGED
@@ -43,21 +43,21 @@ AI uses explore → filters spec by category "composition"
43
43
 
44
44
  ### `tweetclaw` (execute API calls)
45
45
 
46
- Execute authenticated API calls. Auth is injected automatically - the LLM never sees your API key.
46
+ Execute authenticated API calls. Auth is injected automatically - the LLM never sees your API key.
47
47
 
48
48
  ```
49
- You: "Search tweets about AI agents"
49
+ You: "Post a tweet saying 'Hello from TweetClaw!'"
50
50
 
51
- AI uses explore → finds /api/v1/x/tweets/search
52
- AI uses tweetclaw calls the endpoint with auth
53
- → Returns tweet results
51
+ AI uses tweetclaw → finds connected account, posts tweet
52
+ Returns { tweetId, success: true }
54
53
  ```
55
54
 
56
55
  ```
57
- You: "Post a tweet saying 'Hello from TweetClaw!'"
56
+ You: "Search tweets about AI agents"
58
57
 
59
- AI uses tweetclaw → finds connected account, posts tweet
60
- Returns { tweetId, success: true }
58
+ AI uses explore → finds /api/v1/x/tweets/search
59
+ AI uses tweetclaw calls the endpoint with auth
60
+ → Returns tweet results
61
61
  ```
62
62
 
63
63
  ## Commands
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "id": "tweetclaw",
3
3
  "name": "TweetClaw",
4
+ "version": "1.2.0",
4
5
  "description": "Post tweets, reply, like, retweet, follow, DM from your chat - full X/Twitter automation powered by Xquik",
5
6
  "configSchema": {
6
7
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xquik/tweetclaw",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "description": "Post tweets, reply, like, retweet, follow, DM & more from OpenClaw - full X/Twitter automation via Xquik",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "files": [
24
24
  "src/",
25
+ "skills/",
25
26
  "openclaw.plugin.json"
26
27
  ],
27
28
  "keywords": [
@@ -48,7 +49,7 @@
48
49
  },
49
50
  "devDependencies": {
50
51
  "@eslint/js": "^10.0.1",
51
- "@sinclair/typebox": "^0.34.0",
52
+ "@sinclair/typebox": "^0.34.48",
52
53
  "@types/node": "^25.5.0",
53
54
  "@typescript-eslint/eslint-plugin": "^8.57.0",
54
55
  "@typescript-eslint/parser": "^8.57.0",
@@ -0,0 +1,208 @@
1
+ ---
2
+ name: tweetclaw
3
+ description: "OpenClaw plugin for X/Twitter automation. Post tweets, reply, like, retweet, follow, DM, search, extract data, run giveaways, monitor accounts via Xquik. 40+ endpoints, 2 tools (explore + tweetclaw), 2 commands (/xstatus, /xtrends), background event poller."
4
+ homepage: https://xquik.com
5
+ read_when:
6
+ - Posting, replying, liking, retweeting, or following on X/Twitter
7
+ - Searching tweets or looking up X/Twitter users
8
+ - Running giveaway draws from tweet replies
9
+ - Monitoring X/Twitter accounts for new activity
10
+ - Composing algorithm-optimized tweets
11
+ - Extracting bulk data from X/Twitter (followers, replies, communities)
12
+ - Downloading tweet media or uploading images
13
+ - Sending DMs or updating X/Twitter profile
14
+ metadata: {"openclaw":{"emoji":"🐦","primaryEnv":"XQUIK_API_KEY","requires":{"env":["XQUIK_API_KEY"]}}}
15
+ ---
16
+
17
+ # TweetClaw
18
+
19
+ OpenClaw plugin for X/Twitter automation powered by Xquik. Install via:
20
+
21
+ ```bash
22
+ openclaw plugins install @xquik/tweetclaw
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ Set your Xquik API key (get one at [xquik.com/account-manager](https://xquik.com/account-manager)):
28
+
29
+ ```bash
30
+ openclaw config set plugins.entries.tweetclaw.config.apiKey 'xq_YOUR_KEY'
31
+ ```
32
+
33
+ ## Tools
34
+
35
+ TweetClaw registers 2 tools that cover the entire Xquik API (40+ endpoints):
36
+
37
+ ### `explore` (free, no network)
38
+
39
+ Search the API spec to find endpoints. No API calls are made.
40
+
41
+ Example: "What endpoints are available for tweet composition?"
42
+
43
+ The agent writes an async arrow function that filters the in-memory endpoint catalog:
44
+
45
+ ```javascript
46
+ async () => spec.endpoints.filter(e => e.category === 'composition')
47
+ ```
48
+
49
+ ### `tweetclaw` (execute API calls)
50
+
51
+ Execute authenticated API calls. Auth is injected automatically.
52
+
53
+ Example: "Post a tweet saying 'Hello from TweetClaw!'"
54
+
55
+ ```javascript
56
+ async () => {
57
+ const { accounts } = await xquik.request('/api/v1/x/accounts');
58
+ return xquik.request('/api/v1/x/tweets', {
59
+ method: 'POST',
60
+ body: { account: accounts[0].xUsername, text: 'Hello from TweetClaw!' }
61
+ });
62
+ }
63
+ ```
64
+
65
+ ## Commands
66
+
67
+ | Command | Description |
68
+ |---------|-------------|
69
+ | `/xstatus` | Account info, subscription status, usage |
70
+ | `/xtrends` | Trending topics from curated sources |
71
+ | `/xtrends tech` | Trending topics filtered by category |
72
+
73
+ ## Event Notifications
74
+
75
+ When polling is enabled (default), TweetClaw checks for new events every 60 seconds:
76
+
77
+ - Monitor alerts: new tweets, replies, quotes, retweets from monitored accounts
78
+ - Follower changes: gained or lost followers on monitored accounts
79
+
80
+ ## Common Workflows
81
+
82
+ ### Post a tweet
83
+
84
+ ```
85
+ You: "Post a tweet saying 'Hello from TweetClaw!'"
86
+ Agent uses tweetclaw -> finds connected account, posts tweet
87
+ ```
88
+
89
+ ### Reply to a tweet
90
+
91
+ ```
92
+ You: "Reply 'Great thread!' to this tweet: https://x.com/user/status/123"
93
+ Agent uses tweetclaw -> posts reply with reply_to_tweet_id
94
+ ```
95
+
96
+ ### Like, retweet, follow
97
+
98
+ ```
99
+ You: "Like and retweet this tweet, then follow the author"
100
+ Agent uses tweetclaw -> likes tweet, retweets, looks up user ID, follows
101
+ ```
102
+
103
+ ### Send a DM
104
+
105
+ ```
106
+ You: "DM @username saying 'Hey, let's collaborate!'"
107
+ Agent uses tweetclaw -> looks up user ID, sends DM
108
+ ```
109
+
110
+ ### Update profile
111
+
112
+ ```
113
+ You: "Change my bio to 'Building cool stuff' and update my avatar"
114
+ Agent uses tweetclaw -> PATCH /api/v1/x/profile, PATCH /api/v1/x/profile/avatar
115
+ ```
116
+
117
+ ### Upload media and tweet with image
118
+
119
+ ```
120
+ You: "Tweet 'Check this out!' with this image: https://example.com/photo.jpg"
121
+ Agent uses tweetclaw -> uploads media, posts tweet with media_ids
122
+ ```
123
+
124
+ ### Search tweets
125
+
126
+ ```
127
+ You: "Search tweets about AI agents"
128
+ Agent uses tweetclaw -> calls search endpoint with query
129
+ ```
130
+
131
+ ### Run a giveaway draw
132
+
133
+ ```
134
+ You: "Pick 3 random winners from replies to this tweet: https://x.com/..."
135
+ Agent uses tweetclaw -> creates draw with filters
136
+ ```
137
+
138
+ ### Extract bulk data
139
+
140
+ ```
141
+ You: "Extract the last 1000 followers of @elonmusk"
142
+ Agent uses tweetclaw -> estimates cost, creates extraction job
143
+ ```
144
+
145
+ ### Monitor an account
146
+
147
+ ```
148
+ You: "Monitor @elonmusk for new tweets and follower changes"
149
+ Agent uses tweetclaw -> creates monitor with event types
150
+ ```
151
+
152
+ ### Download tweet media
153
+
154
+ ```
155
+ You: "Download all media from this tweet"
156
+ Agent uses tweetclaw -> returns gallery URL with all media
157
+ ```
158
+
159
+ ### Compose an optimized tweet (free)
160
+
161
+ ```
162
+ You: "Help me write a tweet about our product launch"
163
+ Agent uses tweetclaw -> 3-step compose/refine/score workflow
164
+ ```
165
+
166
+ ### Analyze writing style (free)
167
+
168
+ ```
169
+ You: "Analyze @username's tweet style"
170
+ Agent uses tweetclaw -> returns style analysis with tone, patterns, metrics
171
+ ```
172
+
173
+ ### Browse trending topics (free)
174
+
175
+ ```
176
+ You: "What's trending on X right now?"
177
+ Agent uses tweetclaw -> returns curated trending topics from 7 sources
178
+ ```
179
+
180
+ ## API Categories
181
+
182
+ | Category | Examples | Free |
183
+ |----------|---------|------|
184
+ | Write Actions | Post tweets, reply, like, retweet, follow, DM, update profile | No |
185
+ | Media | Upload media, download tweet media | No |
186
+ | Twitter | Search tweets, look up users, check follows | No |
187
+ | Composition | Compose, refine, score tweets; manage drafts | Yes |
188
+ | Styles | Analyze tweet styles, compare, performance | Mixed |
189
+ | Extraction | Reply/follower/community extraction (20 tools) | No |
190
+ | Draws | Giveaway draws, export results | No |
191
+ | Monitoring | Create monitors, view events, webhooks | No |
192
+ | Account | API keys, subscription, connected X accounts | Yes |
193
+ | Trends | X trending topics, curated radar from 7 sources | Mixed |
194
+
195
+ ## Pricing
196
+
197
+ Free tier (no subscription): tweet composition, style analysis, drafts, curated radar, account management, integrations.
198
+
199
+ Subscription ($20/month): write actions, search, media, extractions, draws, monitors, X trending.
200
+
201
+ When a paid endpoint returns 402, TweetClaw provides a checkout URL.
202
+
203
+ ## When NOT to Use
204
+
205
+ - Reading tweets in a browser or basic browsing (use a browser skill instead)
206
+ - X/Twitter analytics dashboards (TweetClaw returns raw data, not visualizations)
207
+ - Scheduling tweets for future posting (Xquik posts immediately)
208
+ - Managing X/Twitter ads or promoted content (not supported)
package/src/index.ts CHANGED
@@ -15,66 +15,64 @@ function isPollerEvent(value: unknown): value is PollerEvent {
15
15
  return typeof value === 'object' && value !== null;
16
16
  }
17
17
 
18
+ function isPluginConfig(value: unknown): value is PluginConfig {
19
+ return typeof value === 'object' && value !== null && 'apiKey' in value;
20
+ }
21
+
18
22
  const DEFAULT_POLLING_INTERVAL_SECONDS = 60;
19
23
 
24
+ interface ToolResult {
25
+ readonly content: ReadonlyArray<{ readonly text: string; readonly type: string }>;
26
+ readonly isError?: true;
27
+ }
28
+
20
29
  interface CommandContext {
21
30
  readonly args?: string;
31
+ readonly commandBody?: string;
32
+ readonly senderId?: string;
22
33
  }
23
34
 
24
35
  interface OpenClawApi {
25
- readonly config: {
26
- readonly plugins?: {
27
- readonly entries?: {
28
- readonly tweetclaw?: {
29
- readonly config?: PluginConfig;
30
- };
31
- };
32
- };
33
- };
34
36
  readonly logger: {
37
+ readonly debug?: (message: string) => void;
38
+ readonly error: (message: string) => void;
35
39
  readonly info: (message: string) => void;
36
40
  readonly warn: (message: string) => void;
37
41
  };
42
+ readonly pluginConfig?: Readonly<Record<string, unknown>>;
38
43
  readonly registerCommand: (options: {
39
- readonly acceptsArguments?: boolean;
44
+ readonly acceptsArgs?: boolean;
40
45
  readonly description: string;
41
46
  readonly handler: (context: CommandContext) => Promise<{ readonly text: string }>;
42
47
  readonly name: string;
43
48
  }) => void;
44
49
  readonly registerService: (options: {
45
50
  readonly id: string;
46
- readonly start: () => void;
47
- readonly stop: () => void;
51
+ readonly start: (context?: unknown) => void;
52
+ readonly stop?: (context?: unknown) => void;
48
53
  }) => void;
49
54
  readonly registerTool: (
50
- options: {
55
+ tool: {
51
56
  readonly description: string;
57
+ readonly execute: (toolCallId: string, params: { readonly code: string }) => Promise<ToolResult>;
52
58
  readonly name: string;
53
- readonly parameters: {
54
- readonly properties: Readonly<Record<string, { readonly description: string; readonly type: string }>>;
55
- readonly required: readonly string[];
56
- readonly type: string;
57
- };
59
+ readonly parameters: unknown;
58
60
  },
59
- handler: (params: { readonly code: string }) => Promise<{
60
- readonly content: ReadonlyArray<{ readonly text: string; readonly type: string }>;
61
- readonly isError?: true;
62
- }>,
61
+ options?: { readonly name?: string; readonly optional?: boolean },
63
62
  ) => void;
64
- readonly sendMessage: (text: string) => void;
65
63
  }
66
64
 
67
65
  const CODE_PARAMETER = {
68
66
  properties: {
69
67
  code: { description: 'Async arrow function to execute', type: 'string' },
70
68
  },
71
- required: ['code'] as const,
69
+ required: ['code'],
72
70
  type: 'object',
73
71
  };
74
72
 
75
73
  export default function register(api: OpenClawApi, fetchFunction?: FetchFunction): void {
76
- const config = api.config.plugins?.entries?.tweetclaw?.config;
77
- if (config?.apiKey === undefined) {
74
+ const config: unknown = api.pluginConfig;
75
+ if (!isPluginConfig(config)) {
78
76
  api.logger.warn(
79
77
  "TweetClaw: No API key configured. Run: openclaw config set plugins.entries.tweetclaw.config.apiKey 'xq_YOUR_KEY'",
80
78
  );
@@ -84,23 +82,25 @@ export default function register(api: OpenClawApi, fetchFunction?: FetchFunction
84
82
  const { apiKey, baseUrl = 'https://xquik.com' } = config;
85
83
  const request = createProxiedRequest(baseUrl, apiKey, fetchFunction);
86
84
 
87
- // --- Tools (2-tool approach) ---
85
+ // --- Tools (2-tool approach, execute inside tool object) ---
88
86
  api.registerTool(
89
87
  {
90
88
  description: SEARCH_DESCRIPTION,
89
+ execute: async (_toolCallId, { code }) => handleExplore(code),
91
90
  name: 'explore',
92
91
  parameters: CODE_PARAMETER,
93
92
  },
94
- async ({ code }) => handleExplore(code),
93
+ { name: 'explore' },
95
94
  );
96
95
 
97
96
  api.registerTool(
98
97
  {
99
98
  description: EXECUTE_DESCRIPTION,
99
+ execute: async (_toolCallId, { code }) => handleTweetclaw({ apiKey, baseUrl, code, fetchFunction }),
100
100
  name: 'tweetclaw',
101
101
  parameters: CODE_PARAMETER,
102
102
  },
103
- async ({ code }) => handleTweetclaw({ apiKey, baseUrl, code, fetchFunction }),
103
+ { name: 'tweetclaw', optional: true },
104
104
  );
105
105
 
106
106
  // --- Commands (instant, no LLM) ---
@@ -114,7 +114,7 @@ export default function register(api: OpenClawApi, fetchFunction?: FetchFunction
114
114
  });
115
115
 
116
116
  api.registerCommand({
117
- acceptsArguments: true,
117
+ acceptsArgs: true,
118
118
  description: 'Show trending topics on X',
119
119
  handler: async ({ args }) => {
120
120
  const text = await handleXTrends(request, args);
@@ -136,7 +136,7 @@ export default function register(api: OpenClawApi, fetchFunction?: FetchFunction
136
136
  const username: string = isPollerEvent(event) && typeof event.xUsername === 'string'
137
137
  ? event.xUsername
138
138
  : '';
139
- api.sendMessage(`[TweetClaw] ${eventType} from @${username}`);
139
+ api.logger.info(`[TweetClaw] ${eventType} from @${username}`);
140
140
  }
141
141
  },
142
142
  request,
@@ -4,7 +4,7 @@ import type { EndpointInfo, ToolResult } from '../types.js';
4
4
 
5
5
  const categories = [...new Set(API_SPEC.map((endpoint) => endpoint.category))].toSorted((a, b) => a.localeCompare(b)).join(', ');
6
6
 
7
- const SEARCH_DESCRIPTION = `Search the X (Twitter) API spec for endpoints: tweet search, user lookup, media download, monitoring, giveaways, composition, and more. No network calls - runs against an in-memory endpoint catalog.
7
+ const SEARCH_DESCRIPTION = `Search the X (Twitter) API spec for endpoints: post tweets, reply, like, retweet, follow, DM, update profile, upload media, search tweets, look up users, extract data, monitor accounts, run giveaways, compose tweets, and more. No network calls - runs against an in-memory endpoint catalog.
8
8
 
9
9
  Write an async arrow function. The sandbox provides:
10
10
 
@@ -2,7 +2,7 @@ import { createProxiedRequest } from '../request.js';
2
2
  import { AsyncFunction, errorResult, specEndpoints, successResult } from './sandbox.js';
3
3
  import type { FetchFunction, RequestFunction, ToolResult } from '../types.js';
4
4
 
5
- const EXECUTE_DESCRIPTION = `Execute X (Twitter) API calls: search tweets, look up users, download media, compose tweets, run giveaways, monitor accounts, and more. Write an async arrow function.
5
+ const EXECUTE_DESCRIPTION = `Execute X (Twitter) API calls: post tweets, reply, like, retweet, follow, DM, update profile, upload media, search tweets, look up users, extract data, run giveaways, monitor accounts, compose tweets, and more. Write an async arrow function.
6
6
 
7
7
  The sandbox provides:
8
8
  \`\`\`typescript
@@ -20,6 +20,13 @@ declare const spec: { endpoints: EndpointInfo[] };
20
20
  Auth is injected automatically - never pass API keys.
21
21
  First use "explore" to find endpoints, then write code here to call them.
22
22
 
23
+ ## Important rules
24
+ - TWEET ACTIONS: SENDING a tweet ("tweet this", "post this") uses POST /api/v1/x/tweets. DRAFTING a tweet ("help me write", "compose") uses the 3-step compose flow. Never use compose when the user has text and wants to send it.
25
+ - CALL ORDERING: NEVER combine free and paid endpoints in Promise.all. Call free endpoints first (radar, styles, compose), then paid ones separately. If a paid call fails with 402, still use free data already fetched.
26
+ - WRITE ACTIONS: All require the "account" parameter (X username, e.g. "@myaccount"). Follow/unfollow/DM use numeric user ID in path - look up the user first via GET /api/v1/x/users/:username.
27
+ - CURRENT EVENTS: Use /api/v1/radar (free) for trending topics. Never use web search for trends.
28
+ - SUBSCRIPTION ERRORS: On 402, call POST /api/v1/subscribe (free) to get checkout URL.
29
+
23
30
  ## Workflows
24
31
 
25
32
  ### 1. Send a tweet (Subscription required)
@@ -103,7 +110,28 @@ async () => {
103
110
  }
104
111
  \`\`\`
105
112
 
106
- ### 7. Search tweets with pagination (Subscription required)
113
+ ### 7. Update profile, avatar, or banner
114
+ \`\`\`javascript
115
+ async () => {
116
+ // Update bio, name, location, URL
117
+ await xquik.request('/api/v1/x/profile', {
118
+ method: 'PATCH',
119
+ body: { account: '@myaccount', name: 'New Name', bio: 'Building cool stuff' }
120
+ });
121
+ // Update avatar (url must be HTTPS, max 700 KB)
122
+ await xquik.request('/api/v1/x/profile/avatar', {
123
+ method: 'PATCH',
124
+ body: { account: '@myaccount', url: 'https://example.com/avatar.jpg' }
125
+ });
126
+ // Update banner (max 2 MB)
127
+ return xquik.request('/api/v1/x/profile/banner', {
128
+ method: 'PATCH',
129
+ body: { account: '@myaccount', url: 'https://example.com/banner.jpg' }
130
+ });
131
+ }
132
+ \`\`\`
133
+
134
+ ### 8. Search tweets with pagination (Subscription required)
107
135
  \`\`\`javascript
108
136
  async () => {
109
137
  // Use limit param for more than 20 results (max 200)
@@ -113,14 +141,87 @@ async () => {
113
141
  }
114
142
  \`\`\`
115
143
 
116
- ### 8. Browse trending topics (FREE)
144
+ ### 9. Look up a user or tweet
145
+ \`\`\`javascript
146
+ async () => {
147
+ // User profile (name, bio, followers, following, verified, location)
148
+ const user = await xquik.request('/api/v1/x/users/elonmusk');
149
+ // Single tweet with full metrics
150
+ const tweet = await xquik.request('/api/v1/x/tweets/1234567890');
151
+ // Check if A follows B
152
+ const follows = await xquik.request('/api/v1/x/followers/check', {
153
+ query: { source: 'userA', target: 'userB' }
154
+ });
155
+ return { user, tweet, follows };
156
+ }
157
+ \`\`\`
158
+
159
+ ### 10. Monitor an account + set up webhook
160
+ \`\`\`javascript
161
+ async () => {
162
+ // Create monitor for new tweets, replies, follower changes
163
+ const monitor = await xquik.request('/api/v1/monitors', {
164
+ method: 'POST',
165
+ body: { username: 'elonmusk', eventTypes: ['tweet.new', 'tweet.reply', 'follower.gained'] }
166
+ });
167
+ // Set up webhook to receive events (save the secret!)
168
+ const webhook = await xquik.request('/api/v1/webhooks', {
169
+ method: 'POST',
170
+ body: { url: 'https://your-server.com/webhook', eventTypes: ['tweet.new', 'tweet.reply'] }
171
+ });
172
+ return { monitor, webhook };
173
+ }
174
+ \`\`\`
175
+
176
+ ### 11. Run a giveaway draw from tweet replies
177
+ \`\`\`javascript
178
+ async () => {
179
+ return xquik.request('/api/v1/draws', {
180
+ method: 'POST',
181
+ body: {
182
+ tweetUrl: 'https://x.com/user/status/1234567890',
183
+ winnerCount: 3,
184
+ backupCount: 2,
185
+ uniqueAuthorsOnly: true,
186
+ mustRetweet: true,
187
+ mustFollowUsername: 'myaccount',
188
+ filterMinFollowers: 50
189
+ }
190
+ });
191
+ }
192
+ \`\`\`
193
+
194
+ ### 12. Extract bulk data (followers, replies, communities)
195
+ \`\`\`javascript
196
+ async () => {
197
+ // Always estimate cost first
198
+ const estimate = await xquik.request('/api/v1/extractions/estimate', {
199
+ method: 'POST',
200
+ body: { toolType: 'follower_explorer', targetUsername: 'elonmusk', resultsLimit: 1000 }
201
+ });
202
+ if (!estimate.allowed) return { error: 'Would exceed quota', estimate };
203
+ // Create extraction job
204
+ const job = await xquik.request('/api/v1/extractions', {
205
+ method: 'POST',
206
+ body: { toolType: 'follower_explorer', targetUsername: 'elonmusk', resultsLimit: 1000 }
207
+ });
208
+ return job;
209
+ // 20 tool types: reply_extractor, repost_extractor, quote_extractor, thread_extractor,
210
+ // article_extractor, follower_explorer, following_explorer, verified_follower_explorer,
211
+ // mention_extractor, post_extractor, community_extractor, community_moderator_explorer,
212
+ // community_post_extractor, community_search, list_member_extractor, list_post_extractor,
213
+ // list_follower_explorer, space_explorer, people_search, tweet_search_extractor
214
+ }
215
+ \`\`\`
216
+
217
+ ### 13. Browse trending topics (FREE)
117
218
  \`\`\`javascript
118
219
  async () => {
119
220
  return xquik.request('/api/v1/radar');
120
221
  }
121
222
  \`\`\`
122
223
 
123
- ### 9. Analyze a user's writing style
224
+ ### 14. Analyze a user's writing style
124
225
  \`\`\`javascript
125
226
  async () => {
126
227
  // Returns cached style if available (free for all users)
@@ -132,7 +233,7 @@ async () => {
132
233
  }
133
234
  \`\`\`
134
235
 
135
- ### 10. Download media and get gallery link (Subscription required)
236
+ ### 15. Download media and get gallery link (Subscription required)
136
237
  \`\`\`javascript
137
238
  async () => {
138
239
  // Returns galleryUrl only (shareable gallery page with all media)
@@ -143,14 +244,42 @@ async () => {
143
244
  }
144
245
  \`\`\`
145
246
 
146
- ### 11. Subscribe (FREE - returns Stripe checkout URL)
247
+ ### 16. Set up Telegram alerts for monitor events (FREE)
248
+ \`\`\`javascript
249
+ async () => {
250
+ return xquik.request('/api/v1/integrations', {
251
+ method: 'POST',
252
+ body: {
253
+ type: 'telegram',
254
+ chatId: '123456789',
255
+ eventTypes: ['tweet.new', 'tweet.reply', 'draw.completed', 'extraction.completed']
256
+ }
257
+ });
258
+ }
259
+ \`\`\`
260
+
261
+ ### 17. Community actions (create, join, leave)
262
+ \`\`\`javascript
263
+ async () => {
264
+ // Join a community
265
+ await xquik.request('/api/v1/x/communities/99999/join', {
266
+ method: 'POST', body: { account: '@myaccount' }
267
+ });
268
+ // Leave a community
269
+ await xquik.request('/api/v1/x/communities/99999/join', {
270
+ method: 'DELETE', body: { account: '@myaccount' }
271
+ });
272
+ }
273
+ \`\`\`
274
+
275
+ ### 18. Subscribe (FREE - returns Stripe checkout URL)
147
276
  \`\`\`javascript
148
277
  async () => {
149
278
  return xquik.request('/api/v1/subscribe', { method: 'POST' });
150
279
  }
151
280
  \`\`\`
152
281
 
153
- ### 12. Draft & optimize tweet text (3-step compose flow, FREE)
282
+ ### 19. Draft & optimize tweet text (3-step compose flow, FREE)
154
283
  \`\`\`javascript
155
284
  async () => {
156
285
  // Use this ONLY when the user wants help WRITING tweet text.