x-developer 2.5.6 → 2.6.2

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.
Files changed (131) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +3 -3
  4. package/CHANGELOG.md +55 -0
  5. package/README.md +201 -18
  6. package/commands/post.md +14 -7
  7. package/commands/trending.md +4 -2
  8. package/context7.json +3 -1
  9. package/openclaw.plugin.json +2 -2
  10. package/package.json +9 -3
  11. package/scripts/check-reproducible.mjs +48 -0
  12. package/scripts/check-versions.mjs +12 -431
  13. package/scripts/release-guard/content-policy.mjs +77 -18
  14. package/scripts/release-guard/context.mjs +61 -0
  15. package/scripts/release-guard/frontmatter.mjs +3 -0
  16. package/scripts/release-guard/policy-checks.mjs +134 -0
  17. package/scripts/release-guard/policy.mjs +4 -1
  18. package/scripts/release-guard/repository-checks.mjs +256 -0
  19. package/server.json +2 -2
  20. package/skills/x-twitter-scraper/SKILL.md +106 -11
  21. package/skills/x-twitter-scraper/metadata.json +1 -1
  22. package/skills/x-twitter-scraper/references/api-endpoints-api-keys.md +6 -23
  23. package/skills/x-twitter-scraper/references/api-endpoints-drafts.md +20 -1
  24. package/skills/x-twitter-scraper/references/api-endpoints-draws.md +26 -0
  25. package/skills/x-twitter-scraper/references/api-endpoints-error-codes.md +3 -0
  26. package/skills/x-twitter-scraper/references/api-endpoints-events.md +3 -1
  27. package/skills/x-twitter-scraper/references/api-endpoints-extractions.md +41 -26
  28. package/skills/x-twitter-scraper/references/api-endpoints-monitors.md +43 -6
  29. package/skills/x-twitter-scraper/references/api-endpoints-radar.md +2 -1
  30. package/skills/x-twitter-scraper/references/api-endpoints-support.md +22 -0
  31. package/skills/x-twitter-scraper/references/api-endpoints-trends.md +9 -1
  32. package/skills/x-twitter-scraper/references/api-endpoints-tweet-style-cache.md +32 -1
  33. package/skills/x-twitter-scraper/references/api-endpoints-webhooks.md +55 -9
  34. package/skills/x-twitter-scraper/references/api-endpoints-x-accounts.md +12 -0
  35. package/skills/x-twitter-scraper/references/api-endpoints-x-api.md +51 -11
  36. package/skills/x-twitter-scraper/references/api-endpoints-x-media.md +10 -0
  37. package/skills/x-twitter-scraper/references/api-endpoints-x-write.md +85 -19
  38. package/skills/x-twitter-scraper/references/automate-twitter-giveaways.md +130 -0
  39. package/skills/x-twitter-scraper/references/best-x-api-alternative.md +198 -0
  40. package/skills/x-twitter-scraper/references/compare-twitter-apis.md +152 -0
  41. package/skills/x-twitter-scraper/references/draws.md +1 -1
  42. package/skills/x-twitter-scraper/references/export-twitter-followers.md +127 -0
  43. package/skills/x-twitter-scraper/references/extract-x-community-data.md +121 -0
  44. package/skills/x-twitter-scraper/references/extractions.md +74 -6
  45. package/skills/x-twitter-scraper/references/mcp-setup.md +14 -5
  46. package/skills/x-twitter-scraper/references/mcp-tools.md +14 -4
  47. package/skills/x-twitter-scraper/references/monitor-twitter-webhooks.md +122 -0
  48. package/skills/x-twitter-scraper/references/python-examples.md +39 -12
  49. package/skills/x-twitter-scraper/references/reliable-twitter-data-api-2026.md +241 -0
  50. package/skills/x-twitter-scraper/references/scrape-export-twitter-data.md +171 -0
  51. package/skills/x-twitter-scraper/references/track-twitter-keywords-mentions.md +148 -0
  52. package/skills/x-twitter-scraper/references/twitter-api-alternative-faq.md +128 -0
  53. package/skills/x-twitter-scraper/references/twitter-api-without-x-account.md +111 -0
  54. package/skills/x-twitter-scraper/references/twitter-data-pipeline.md +136 -0
  55. package/skills/x-twitter-scraper/references/twitter-scraper-api-guide.md +229 -0
  56. package/skills/x-twitter-scraper/references/types-events.md +5 -25
  57. package/skills/x-twitter-scraper/references/types-extractions.md +49 -2
  58. package/skills/x-twitter-scraper/references/types-mcp-output-schemas.md +10 -19
  59. package/skills/x-twitter-scraper/references/types-monitors.md +30 -1
  60. package/skills/x-twitter-scraper/references/types-radar.md +7 -0
  61. package/skills/x-twitter-scraper/references/types-rest-api-vs-mcp-field-naming.md +8 -12
  62. package/skills/x-twitter-scraper/references/types-trends.md +3 -0
  63. package/skills/x-twitter-scraper/references/types-webhooks.md +10 -2
  64. package/skills/x-twitter-scraper/references/types-x-api.md +93 -12
  65. package/skills/x-twitter-scraper/references/types-x-articles.md +27 -12
  66. package/skills/x-twitter-scraper/references/types-x-write.md +46 -7
  67. package/skills/x-twitter-scraper/references/types.md +0 -17
  68. package/skills/x-twitter-scraper/references/webhooks.md +123 -35
  69. package/skills/x-twitter-scraper/references/workflows.md +27 -9
  70. package/skills/x-twitter-scraper/skill-card.md +2 -2
  71. package/skills/x-twitter-scraper/skillspector-report.md +5 -2
  72. package/skills/xquik-social-research/SKILL.md +1 -0
  73. package/start.sh +3 -0
  74. package/stub-server.mjs +91 -50
  75. package/task-guides/check-mutuals.md +1 -1
  76. package/task-guides/clean-followers.md +1 -1
  77. package/task-guides/export-tweets-csv.md +14 -5
  78. package/task-guides/extract-followers.md +2 -2
  79. package/task-guides/find-bangers.md +4 -2
  80. package/task-guides/find-influencers.md +7 -4
  81. package/task-guides/find-viral-tweets.md +1 -1
  82. package/task-guides/follow-unfollow.md +9 -4
  83. package/task-guides/for-you-feed.md +1 -1
  84. package/task-guides/going-viral.md +1 -1
  85. package/task-guides/grow-followers.md +4 -2
  86. package/task-guides/monitor-accounts.md +8 -9
  87. package/task-guides/optimize-tweets.md +1 -1
  88. package/task-guides/post-tweets.md +11 -7
  89. package/task-guides/run-giveaway.md +1 -1
  90. package/task-guides/search-tweets.md +16 -8
  91. package/task-guides/send-dms.md +16 -7
  92. package/task-guides/top-replies.md +25 -9
  93. package/task-guides/track-competitors.md +3 -3
  94. package/task-guides/track-hashtags.md +7 -8
  95. package/task-guides/track-mentions.md +10 -9
  96. package/task-guides/trending-news.md +13 -8
  97. package/task-guides/tweet-analytics.md +2 -2
  98. package/task-guides/tweet-ideas.md +1 -1
  99. package/task-guides/tweet-replies.md +63 -14
  100. package/task-guides/tweet-style.md +1 -1
  101. package/task-guides/tweet-webhooks.md +16 -12
  102. package/task-guides/update-x-profile.md +8 -5
  103. package/task-guides/user-tweets.md +20 -8
  104. package/task-guides/who-liked.md +1 -1
  105. package/task-guides/who-quoted.md +1 -1
  106. package/task-guides/who-retweeted.md +1 -1
  107. package/task-guides/write-threads.md +1 -1
  108. package/task-guides/write-tweets.md +1 -1
  109. package/task-guides/x-articles.md +10 -5
  110. package/task-guides/x-bookmarks.md +1 -1
  111. package/task-guides/x-communities.md +1 -1
  112. package/task-guides/x-lists.md +1 -1
  113. package/task-guides/x-spaces.md +1 -1
  114. package/task-guides/x-trends.md +6 -6
  115. package/skills/x-twitter-scraper/references/types-mcp-add-webhook.md +0 -14
  116. package/skills/x-twitter-scraper/references/types-mcp-check-follow.md +0 -10
  117. package/skills/x-twitter-scraper/references/types-mcp-compose-tweet.md +0 -31
  118. package/skills/x-twitter-scraper/references/types-mcp-estimate-extraction.md +0 -15
  119. package/skills/x-twitter-scraper/references/types-mcp-get-account.md +0 -26
  120. package/skills/x-twitter-scraper/references/types-mcp-get-draw.md +0 -30
  121. package/skills/x-twitter-scraper/references/types-mcp-get-events.md +0 -19
  122. package/skills/x-twitter-scraper/references/types-mcp-get-trends.md +0 -16
  123. package/skills/x-twitter-scraper/references/types-mcp-get-user-info.md +0 -16
  124. package/skills/x-twitter-scraper/references/types-mcp-list-monitors.md +0 -15
  125. package/skills/x-twitter-scraper/references/types-mcp-lookup-tweet.md +0 -25
  126. package/skills/x-twitter-scraper/references/types-mcp-refine-tweet.md +0 -13
  127. package/skills/x-twitter-scraper/references/types-mcp-run-draw.md +0 -18
  128. package/skills/x-twitter-scraper/references/types-mcp-run-extraction.md +0 -12
  129. package/skills/x-twitter-scraper/references/types-mcp-score-tweet.md +0 -16
  130. package/skills/x-twitter-scraper/references/types-mcp-search-tweets.md +0 -17
  131. package/skills/x-twitter-scraper/references/types-mcp-test-webhook.md +0 -11
@@ -2,6 +2,23 @@
2
2
 
3
3
  23 bulk data extraction tools. Each requires a specific target parameter.
4
4
 
5
+ ## Privacy and Acceptable Use
6
+
7
+ Bulk extraction and export can collect large amounts of public identity,
8
+ activity, and relationship data. Before creating a job, confirm the lawful
9
+ purpose, target, `resultsLimit`, intended recipients, and retention period.
10
+ Follow X rules and applicable privacy law. Do not use these tools for
11
+ credential collection, private data, surveillance, discrimination, harassment,
12
+ doxxing, or unrelated secondary use. Delete exported data when the approved
13
+ purpose ends.
14
+
15
+ Every extraction requires an estimate and explicit approval for the exact
16
+ bounded job. Never infer approval from a general request or increase a bound
17
+ without renewed approval.
18
+
19
+ The API accepts an omitted `resultsLimit`. This Skill must always send an
20
+ explicit finite positive bound. Use the same bound for estimate and create.
21
+
5
22
  **Endpoint:** `POST /extractions`
6
23
 
7
24
  **Always estimate first:** `POST /extractions/estimate` with the same body to preview `creditsRequired`, `creditsAvailable`, and whether the job is allowed.
@@ -55,7 +72,7 @@
55
72
 
56
73
  The `@` prefix is automatically stripped if included.
57
74
 
58
- ### User-Based by ID (require `targetUserId`)
75
+ ### User Timeline Tools (require `targetUsername`)
59
76
 
60
77
  | Tool Type | Description |
61
78
  |-----------|-------------|
@@ -66,7 +83,7 @@ The `@` prefix is automatically stripped if included.
66
83
  ```json
67
84
  {
68
85
  "toolType": "user_likes",
69
- "targetUserId": "44196397"
86
+ "targetUsername": "elonmusk"
70
87
  }
71
88
  ```
72
89
 
@@ -122,7 +139,7 @@ The `@` prefix is automatically stripped if included.
122
139
  | Tool Type | Description |
123
140
  |-----------|-------------|
124
141
  | `people_search` | Search for users by keyword |
125
- | `tweet_search_extractor` | Search and extract tweets by keyword or hashtag (bulk, up to 1,000) |
142
+ | `tweet_search_extractor` | Search and extract tweets by keyword or hashtag |
126
143
 
127
144
  **Example (people search):**
128
145
  ```json
@@ -143,7 +160,8 @@ The `@` prefix is automatically stripped if included.
143
160
 
144
161
  ### Tweet Search Filters
145
162
 
146
- The `tweet_search_extractor` tool type supports 16 additional filter fields that are converted to X search operators and combined with `searchQuery`:
163
+ `tweet_search_extractor` accepts structured filters. It combines them with
164
+ `searchQuery` before collection.
147
165
 
148
166
  | Field | Type | Description |
149
167
  |-------|------|-------------|
@@ -153,15 +171,49 @@ The `tweet_search_extractor` tool type supports 16 additional filter fields that
153
171
  | `language` | string | Language code (e.g., `en`) |
154
172
  | `sinceDate` | string | Start date (YYYY-MM-DD) |
155
173
  | `untilDate` | string | End date (YYYY-MM-DD) |
156
- | `mediaType` | string | `images`, `videos`, `gifs`, or `media` |
174
+ | `mediaType` | string | `images`, `videos`, `gifs`, `media`, `links`, or `none` |
157
175
  | `minFaves` | number | Minimum likes |
158
176
  | `minRetweets` | number | Minimum retweets |
159
177
  | `minReplies` | number | Minimum replies |
178
+ | `minQuotes` | number | Minimum quote count |
179
+ | `minViews` | number | Minimum view count |
180
+ | `minBookmarks` | number | Minimum bookmark count |
181
+ | `maxLikes` | number | Maximum likes |
182
+ | `maxRetweets` | number | Maximum reposts |
183
+ | `maxReplies` | number | Maximum replies |
184
+ | `maxQuotes` | number | Maximum quotes |
185
+ | `blueVerifiedOnly` | boolean | Blue-verified authors only |
186
+ | `cardName` | string | Match the Tweet card name |
187
+ | `source` | string | Match the source application |
188
+ | `excludeSource` | string | Exclude a source application |
189
+ | `geocode` | string | Match latitude, longitude, and radius |
190
+ | `sinceId` | string | Tweets newer than this ID |
191
+ | `maxId` | string | Tweets older than this ID |
192
+ | `near` | string | Match a place name |
193
+ | `within` | string | Radius for the `near` filter |
194
+ | `withinTime` | string | Recent time window |
195
+ | `nativeRetweets` | boolean | Native reposts only |
196
+ | `safe` | boolean | Enable safe search |
197
+ | `news` | boolean | News results only |
160
198
  | `verifiedOnly` | boolean | Verified authors only |
161
199
  | `replies` | string | `include`, `exclude`, or `only` |
162
200
  | `retweets` | string | `include`, `exclude`, or `only` |
201
+ | `quotes` | string | `include`, `exclude`, or `only` |
163
202
  | `exactPhrase` | string | Exact match text |
164
203
  | `excludeWords` | string | Comma-separated words to exclude |
204
+ | `anyWords` | string | Terms where any one can match |
205
+ | `hashtags` | string | Hashtags separated by spaces, commas, or lines |
206
+ | `cashtags` | string | Cashtags separated by spaces, commas, or lines |
207
+ | `url` | string | URL substring or domain |
208
+ | `conversationId` | string | Conversation ID |
209
+ | `inReplyToTweetId` | string | Replies to one Tweet ID |
210
+ | `quotesOfTweetId` | string | Quotes of one Tweet ID |
211
+ | `retweetsOfTweetId` | string | Reposts of one Tweet ID |
212
+ | `listId` | string | Search within a list |
213
+ | `place` | string | Search within a place ID |
214
+ | `placeCountry` | string | Search within a country code |
215
+ | `pointRadius` | string | Geographic point and radius |
216
+ | `boundingBox` | string | Geographic bounding box |
165
217
  | `advancedQuery` | string | Raw X search operators appended to query |
166
218
 
167
219
  **Example with filters:**
@@ -179,6 +231,13 @@ The `tweet_search_extractor` tool type supports 16 additional filter fields that
179
231
 
180
232
  `resultsLimit` (optional): Maximum results to extract. Stops early instead of fetching all. Pass this on both `POST /extractions/estimate` and `POST /extractions` when you only need a specific count.
181
233
 
234
+ ### Profile Filters
235
+
236
+ Profile-producing extractions also accept `minFollowers`, `maxFollowers`,
237
+ `minFollowing`, `maxFollowing`, `minPosts`, `maxPosts`,
238
+ `minAccountAgeDays`, `verifiedType`, `hasWebsite`, `hasLocation`,
239
+ `bioContains`, `locationContains`, and `usernameContains`.
240
+
182
241
  ## Response
183
242
 
184
243
  ```json
@@ -214,6 +273,14 @@ Formats: `csv`, `json`, `md`, `md-document`, `pdf`, `txt`, `xlsx`. 100,000 row l
214
273
 
215
274
  Exports include enrichment columns not present in the API response.
216
275
 
276
+ The endpoint supports follower, following, post, engagement, profile, media,
277
+ language, search, and date filters. It does not project individual fields.
278
+
279
+ **Approval required:** Set the smallest approved `resultsLimit` when creating
280
+ the job. Before export, show the job, filters, format, row count, schema,
281
+ recipients, storage, and retention. Materialize or transmit the dataset only
282
+ after explicit approval. Delete it when the approved purpose ends.
283
+
217
284
  ## Estimating Usage
218
285
 
219
286
  ```
@@ -232,6 +299,7 @@ Same body as create. Response:
232
299
  }
233
300
  ```
234
301
 
235
- If `allowed` is `false`, the extraction requires more credits than are currently available.
302
+ If `allowed` is `false`, do not create the extraction. It requires more credits
303
+ than are currently available.
236
304
 
237
305
  For common mistakes and tool selection rules, see [mcp-tools.md](mcp-tools.md#common-mistakes).
@@ -10,7 +10,15 @@ API keys.
10
10
  | Protocol | Streamable HTTP |
11
11
  | Endpoint | `https://xquik.com/mcp` |
12
12
  | Authentication | OAuth 2.1 discovery; API key fallback |
13
- | Version | `2.5.6` |
13
+ | Hosted MCP version | `2.6.0` |
14
+ | Skill bundle version | `2.6.2` |
15
+
16
+ Current clients negotiate MCP `2026-07-28` through `server/discover`.
17
+ Use a current MCP SDK. It adds request `_meta` and protocol headers.
18
+ Modern calls need no `initialize` request or session ID.
19
+ Discovery and tool catalogs include private 5-minute cache hints.
20
+ Reuse cached metadata only with the same authorization context.
21
+ Stateless 2025-era clients remain compatible at the same endpoint.
14
22
 
15
23
  Xquik publishes these discovery documents:
16
24
 
@@ -275,12 +283,13 @@ this fallback. Codex uses the `bearer_token_env_var` configuration above.
275
283
  Client schemas and environment syntax differ, so do not copy a generic header
276
284
  object between clients or place a literal key in a configuration file.
277
285
 
278
- Full account keys expose 119 catalog routes. Of these, 118 support JSON or text.
286
+ Full account keys expose 120 catalog routes. Of these, 119 support JSON or text.
279
287
  Active guest `paid_reads` keys expose 33 eligible GET routes.
280
288
 
281
289
  ## MCP Server Architecture
282
290
 
283
- The MCP server (v2.5.6) exposes 119 catalog routes through 2 structured API tools. Of these, 118 support JSON or text. Binary support downloads use REST.
291
+ Hosted MCP v2.6.0 exposes 120 catalog routes through 2 structured API tools.
292
+ Of these, 119 support JSON or text. Binary support downloads use REST.
284
293
 
285
294
  | Tool | Description | Usage |
286
295
  |------|-------------|------|
@@ -291,8 +300,8 @@ The MCP server (v2.5.6) exposes 119 catalog routes through 2 structured API tool
291
300
  operations with normalized snake_case responses. Authentication is injected, so
292
301
  tool code must never include credentials.
293
302
 
294
- MCP v2.5.6 catalogs 119 of 127 documented REST operations. These 8 credential
295
- or session operations remain direct REST or dashboard workflows:
303
+ Hosted MCP v2.6.0 catalogs 120 of 128 documented REST operations. These 8 credential,
304
+ checkout, or guest-wallet operations remain direct REST or dashboard workflows:
296
305
 
297
306
  - API key creation, listing, and revocation
298
307
  - Saved-payment top-up
@@ -2,6 +2,10 @@
2
2
 
3
3
  The MCP server at `https://xquik.com/mcp` provides 2 structured API tools. The agent sends API requests through the server, which handles authentication and execution for `xquik.com/api/v1`.
4
4
 
5
+ Hosted MCP v2.6.0 supports `2026-07-28` through `server/discover`.
6
+ Current MCP SDKs add request metadata and headers automatically.
7
+ Modern calls need no initialization session.
8
+
5
9
  ## Contents
6
10
 
7
11
  - [Tools](#tools)
@@ -31,6 +35,7 @@ interface EndpointInfo {
31
35
  category: string; // account, composition, credits, extraction, media, monitoring, support, twitter, x-accounts, x-write
32
36
  free: boolean; // Included usage flag from endpoint metadata
33
37
  parameters?: Array<{ name: string; in: 'query' | 'path' | 'body'; required: boolean; type: string; description: string }>;
38
+ injectedHeaders?: string[];
34
39
  responseShape?: string;
35
40
  }
36
41
 
@@ -52,7 +57,7 @@ async () => spec.endpoints.filter(e => e.summary.toLowerCase().includes('tweet')
52
57
 
53
58
  ### `xquik` - Send API Requests
54
59
 
55
- The tool provides `xquik.request()` with auth injected automatically. Never pass API keys.
60
+ The tool provides `xquik.request()` with authentication and required idempotency headers injected automatically. Never pass API keys or headers. The sandbox reuses each generated key for bounded transient retries. After an unresolved write failure, verify state. Start a new attempt only when `safe_to_retry` is true and the user approves.
56
61
 
57
62
  ## Safety Gates
58
63
 
@@ -124,7 +129,7 @@ Use `explore` first to find endpoints, then `xquik` to call them.
124
129
  | Get bookmark folders | `GET /api/v1/x/bookmarks/folders` |
125
130
  | Get notifications | `GET /api/v1/x/notifications` (private; confirmation required) |
126
131
  | Get home timeline | `GET /api/v1/x/timeline` (private; confirmation required) |
127
- | Get DM history | `GET /api/v1/x/dm/{userId}/history` (private; confirmation required) |
132
+ | Get DM history | `GET /api/v1/x/dm/{userId}/history?account={username}` (private; exact-account approval required; block ambiguous selection) |
128
133
  | Check credit balance | `GET /api/v1/credits` |
129
134
 
130
135
  Use `POST /api/v1/extractions` ONLY for bulk data that simpler endpoints cannot provide (all followers, all replies to a tweet, community members, etc.). Always call `POST /api/v1/extractions/estimate` first.
@@ -138,9 +143,10 @@ Use `POST /api/v1/extractions` ONLY for bulk data that simpler endpoints cannot
138
143
  | **Bulk extraction** | `POST /extractions/estimate` -> `POST /extractions` -> `GET /extractions/{id}` |
139
144
  | **Compose optimized tweet** | `POST /compose` (step=compose -> refine -> score) |
140
145
  | **Analyze tweet style** | `POST /styles` -> `GET /styles/{id}` -> `POST /compose` with `styleUsername` |
141
- | **Post a tweet** | `GET /x/accounts` -> `POST /x/tweets` with `account` + `text` |
146
+ | **Post a tweet** | `GET /x/accounts` -> confirm -> `POST /x/tweets` with `account` and `text` -> hosted MCP injects a unique `Idempotency-Key` -> poll `statusUrl` |
142
147
  | **Get trending news** | `GET /radar` (supported sources, via `xquik` tool) -> `POST /compose` with trending topic |
143
148
  | **Open support ticket** | `POST /support/tickets` -> `GET /support/tickets/{id}` |
149
+ | **Collect maximum-coverage replies** | `GET /x/tweets/{id}/replies?mode=complete&limit=<1-25000>` -> filter direct rows by `inReplyToId` -> keep `nested_replies` separate -> inspect `diagnostic` |
144
150
 
145
151
  ## Common Mistakes
146
152
 
@@ -154,10 +160,14 @@ Use `POST /api/v1/extractions` ONLY for bulk data that simpler endpoints cannot
154
160
  | Passing API keys in code | Auth is injected automatically. Never include keys |
155
161
  | Using `explore` for API calls | `explore` is read-only spec search. Use `xquik` for actual API calls |
156
162
  | Looking up follow/DM by username | Follow and DM endpoints need numeric user ID. Look up via `GET /x/users/{id}` first; that route accepts usernames and IDs |
163
+ | Treating nested replies as direct replies | Match `inReplyToId` to the root ID. Keep `nested_replies` separate |
164
+ | Treating 424 as an empty failure | Keep safe partial rows. Follow `diagnostic.recommendedFallback` and disclose coverage |
157
165
 
158
166
  ## REST-only operations
159
167
 
160
- MCP v2.5.6 catalogs 119 of 127 REST operations. Of these, 118 support JSON or text. Binary support downloads use REST. These 8 credential or session operations remain outside MCP:
168
+ Hosted MCP v2.6.0 catalogs 120 of 128 REST operations.
169
+ Of these, 119 support JSON or text. Binary support downloads use REST.
170
+ These 8 credential, checkout, or guest-wallet operations remain outside MCP:
161
171
 
162
172
  - API key creation
163
173
  - API key listing
@@ -0,0 +1,122 @@
1
+ # Twitter Account Monitor API: HMAC Webhook Alerts
2
+
3
+ Xquik account monitors can detect new tweets, replies, quotes, and reposts.
4
+ Keyword monitors detect new matches for a persistent query. Poll events or push
5
+ them to an HTTPS endpoint through HMAC-signed webhooks.
6
+
7
+ > Xquik is an independent third-party service. Not affiliated with X Corp.
8
+ > "Twitter" and "X" are trademarks of X Corp.
9
+
10
+ ## Twitter Monitor Event and Delivery Data
11
+
12
+ | Object | Fields to Preserve |
13
+ | --- | --- |
14
+ | Account monitor | Monitor ID, username, event types, active state |
15
+ | Keyword monitor | Monitor ID, query, event types, active state |
16
+ | Event | Event ID, monitor ID and type, event type, occurrence time, data |
17
+ | Delivery | Delivery ID, stream event ID, attempts, status, delivery time |
18
+
19
+ ## Twitter Monitor Polling Versus Webhook Delivery
20
+
21
+ | Requirement | Poll Events | Webhook Delivery |
22
+ | --- | --- | --- |
23
+ | Simple scheduled batch | Strong fit | Optional |
24
+ | Low detection delay | More frequent polling needed | Strong fit |
25
+ | Recover after downtime | Resume with the stored cursor | Inspect delivery status, then repoll events |
26
+ | Public HTTPS endpoint | Not required | Required |
27
+ | Signature verification | Not applicable | Required |
28
+ | Backpressure control | Caller controls fetch rate | Receiver must queue work |
29
+
30
+ Both models need idempotency. Persist the event before downstream processing.
31
+ Mark completion only after every required side effect succeeds.
32
+
33
+ ### What is the best way to monitor a Twitter account programmatically?
34
+
35
+ Validate the public account and required event types first. Use a bounded
36
+ timeline read for an initial snapshot. Create a persistent account monitor only
37
+ after reviewing target, filters, ongoing usage, delivery, and deletion.
38
+
39
+ Poll events when the application controls scheduling. Use webhooks when low
40
+ detection delay matters. Measure delay, duplicate deliveries, missed known
41
+ events, retry behavior, and outage recovery.
42
+
43
+ ### How do I monitor Twitter mentions?
44
+
45
+ Use a mention search or `mention_extractor` for a bounded historical dataset.
46
+ Use a keyword or account monitor for new mention events. Keep explicit account
47
+ mentions separate from broad brand keyword matches.
48
+
49
+ Add exact phrases, exclusions, language, author, and engagement rules to improve
50
+ precision. Review a sample and version every query change.
51
+
52
+ ### What are Twitter webhook alerts?
53
+
54
+ Webhook alerts are HTTPS POST requests sent when a monitor creates a matching
55
+ event. Xquik signs each delivery with a per-webhook HMAC secret. The secret is
56
+ shown only once and should enter a secret store immediately.
57
+
58
+ Verify `<timestamp>.<nonce>.<raw body>` with `X-Xquik-Timestamp`,
59
+ `X-Xquik-Nonce`, and `X-Xquik-Signature`. Reject timestamps outside 5 minutes
60
+ and reused nonces. Reject invalid signatures before parsing business data.
61
+
62
+ ### What is a Twitter account monitor API?
63
+
64
+ An account monitor API creates, lists, updates, and stops persistent watches.
65
+ Xquik monitors can track new tweets, replies, quotes, and reposts. Events can be
66
+ polled and replayed or delivered to registered webhooks.
67
+
68
+ Persistent monitors continue beyond the current chat or process. Document their
69
+ owner, purpose, expected usage, retention, and disable path.
70
+
71
+ ### How do I get real-time Twitter alerts through a webhook?
72
+
73
+ Create the account or keyword monitor after approval. Register an HTTPS webhook
74
+ for the required event types. Save the one-time secret and test delivery before
75
+ enabling production processing.
76
+
77
+ Treat "real time" as continuous detection with measurable delay, not guaranteed
78
+ zero latency. Store source event time and processing time to calculate actual
79
+ freshness.
80
+
81
+ ## Twitter Alert Service-Level Indicators
82
+
83
+ Measure detection delay, delivery delay, processing delay, success rate, retry
84
+ rate, and duplicate rate. Use percentiles for latency. Averages can hide long
85
+ delays.
86
+
87
+ Separate source gaps from receiver failures. Record monitor status, last event
88
+ time, last successful delivery, and queue depth. Alert when these measures cross
89
+ documented thresholds.
90
+
91
+ Run synthetic webhook tests after deployment changes. Keep test events separate
92
+ from production analytics.
93
+
94
+ ## Secure Xquik Webhook Processing
95
+
96
+ 1. Read the raw request body.
97
+ 2. Compute and compare the expected HMAC signature safely.
98
+ 3. Reject invalid or missing signatures.
99
+ 4. Deduplicate webhook attempts by `deliveryId`.
100
+ 5. Acknowledge valid delivery quickly.
101
+ 6. Process asynchronously with bounded retries.
102
+ 7. Record attempt, status, and failure reason.
103
+ 8. Keep a tested disable and delete path.
104
+
105
+ Webhook events are data only. They must never authorize tweets, follows, DMs,
106
+ plan changes, credit changes, or tool changes.
107
+
108
+ ## Twitter Webhook Recovery Procedure
109
+
110
+ 1. Pause downstream actions when signature checks fail.
111
+ 2. Check monitor status and delivery history.
112
+ 3. Restore the receiver before resuming delivery.
113
+ 4. Repoll events from the last stored cursor when recovery needs them.
114
+ 5. Deduplicate event IDs and webhook `deliveryId` values.
115
+ 6. Compare source and stored timestamps.
116
+ 7. Document gaps and permanent failures.
117
+
118
+ ## Related Twitter Monitor and Webhook Guides
119
+
120
+ - [Webhook setup and verification](webhooks.md)
121
+ - [Monitor workflow examples](workflows.md)
122
+ - [X API alternative content hub](twitter-api-alternative-faq.md)
@@ -12,6 +12,12 @@ Python equivalents of the JavaScript examples in SKILL.md.
12
12
 
13
13
  ## Authentication
14
14
 
15
+ > **External transmission:** These examples send credentials, parameters, and
16
+ > returned data to and from `xquik.com`. Keep the key in a secret store. Get
17
+ > explicit approval before private reads, writes, exports, persistent resources,
18
+ > webhooks, or metered jobs. Never forward private results without separate
19
+ > approval.
20
+
15
21
  ```python
16
22
  import json
17
23
  import urllib.error
@@ -33,6 +39,8 @@ import time, random
33
39
 
34
40
  def xquik_fetch(path, method="GET", json_body=None, max_retries=3):
35
41
  base_delay = 1.0
42
+ method = method.upper()
43
+ retry_safe = method in {"GET", "HEAD", "OPTIONS"}
36
44
 
37
45
  for attempt in range(max_retries + 1):
38
46
  retry_after = None
@@ -49,7 +57,7 @@ def xquik_fetch(path, method="GET", json_body=None, max_retries=3):
49
57
  payload = json.loads(error.read() or b"{}")
50
58
  retry_after = error.headers.get("Retry-After")
51
59
 
52
- retryable = status == 429 or status >= 500
60
+ retryable = retry_safe and (status == 429 or status >= 500)
53
61
  if not retryable or attempt == max_retries:
54
62
  raise Exception(f"Xquik API {status}: {payload.get('error', 'request failed')}")
55
63
 
@@ -60,10 +68,18 @@ def xquik_fetch(path, method="GET", json_body=None, max_retries=3):
60
68
  ## Extraction Workflow
61
69
 
62
70
  ```python
71
+ RESULTS_LIMIT = 1000
72
+
73
+ def require_explicit_approval(scope: str) -> None:
74
+ raise RuntimeError(
75
+ f"Approval required for {scope}. Implement the approval gate first."
76
+ )
77
+
63
78
  # Step 1: Estimate
64
79
  estimate = xquik_fetch("/extractions/estimate", method="POST", json_body={
65
80
  "toolType": "reply_extractor",
66
81
  "targetTweetId": "1893704267862470862",
82
+ "resultsLimit": RESULTS_LIMIT,
67
83
  })
68
84
 
69
85
  if not estimate["allowed"]:
@@ -71,9 +87,13 @@ if not estimate["allowed"]:
71
87
  exit()
72
88
 
73
89
  # Step 2: Create job
90
+ require_explicit_approval(
91
+ "the bounded extraction job, usage, recipients, and retention"
92
+ )
74
93
  job = xquik_fetch("/extractions", method="POST", json_body={
75
94
  "toolType": "reply_extractor",
76
95
  "targetTweetId": "1893704267862470862",
96
+ "resultsLimit": RESULTS_LIMIT,
77
97
  })
78
98
 
79
99
  # Step 3: Poll until complete (large jobs may return "running")
@@ -88,7 +108,7 @@ results = []
88
108
  while True:
89
109
  path = f"/extractions/{job['id']}"
90
110
  if cursor:
91
- path += f"?after={cursor}"
111
+ path += f"?cursor={cursor}"
92
112
  page = xquik_fetch(path)
93
113
  results.extend(page["results"])
94
114
 
@@ -128,6 +148,8 @@ for winner in details["winners"]:
128
148
  import hashlib
129
149
  import hmac
130
150
  import json
151
+ import re
152
+ import time
131
153
  from http.server import BaseHTTPRequestHandler, HTTPServer
132
154
 
133
155
  def load_secret(name: str) -> str:
@@ -136,10 +158,15 @@ def load_secret(name: str) -> str:
136
158
 
137
159
  # Per-webhook secret from POST /webhooks response, not a Xquik account credential
138
160
  WEBHOOK_SECRET = load_secret("XQUIK_WEBHOOK_SECRET")
139
- processed_hashes = set() # Use Redis/DB in production
140
-
141
- def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
142
- expected = "sha256=" + hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
161
+ processed_delivery_ids = set() # Use durable storage in production
162
+
163
+ def verify_signature(payload: bytes, signature: str, timestamp: str, nonce: str, secret: str) -> bool:
164
+ if not timestamp.isdigit() or not re.fullmatch(r"[0-9a-f]{32}", nonce):
165
+ return False
166
+ if abs(int(time.time() * 1000) - int(timestamp)) > 5 * 60 * 1000:
167
+ return False
168
+ signing_input = timestamp.encode() + b"." + nonce.encode() + b"." + payload
169
+ expected = "sha256=" + hmac.new(secret.encode(), signing_input, hashlib.sha256).hexdigest()
143
170
  return hmac.compare_digest(expected, signature)
144
171
 
145
172
  EVENT_HANDLERS = {
@@ -153,23 +180,23 @@ class WebhookHandler(BaseHTTPRequestHandler):
153
180
  def do_POST(self):
154
181
  length = int(self.headers.get("Content-Length", "0"))
155
182
  signature = self.headers.get("X-Xquik-Signature", "")
183
+ timestamp = self.headers.get("X-Xquik-Timestamp", "")
184
+ nonce = self.headers.get("X-Xquik-Nonce", "")
156
185
  payload = self.rfile.read(length)
157
186
 
158
- if not verify_signature(payload, signature, WEBHOOK_SECRET):
187
+ if not verify_signature(payload, signature, timestamp, nonce, WEBHOOK_SECRET):
159
188
  self.send_response(401)
160
189
  self.end_headers()
161
190
  self.wfile.write(b"Invalid signature")
162
191
  return
163
192
 
164
- payload_hash = hashlib.sha256(payload).hexdigest()
165
- if payload_hash in processed_hashes:
193
+ event = json.loads(payload)
194
+ if event["deliveryId"] in processed_delivery_ids:
166
195
  self.send_response(200)
167
196
  self.end_headers()
168
197
  self.wfile.write(b"Already processed")
169
198
  return
170
- processed_hashes.add(payload_hash)
171
-
172
- event = json.loads(payload)
199
+ processed_delivery_ids.add(event["deliveryId"])
173
200
  handler = EVENT_HANDLERS.get(event["eventType"])
174
201
  if handler:
175
202
  handler(event["username"], event["data"])