x-developer 2.4.8 → 2.4.9

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 (54) hide show
  1. package/README.md +32 -30
  2. package/openclaw.plugin.json +2 -2
  3. package/package.json +3 -3
  4. package/skills/check-mutuals/SKILL.md +2 -0
  5. package/skills/clean-followers/SKILL.md +2 -0
  6. package/skills/export-tweets-csv/SKILL.md +2 -0
  7. package/skills/extract-followers/SKILL.md +3 -1
  8. package/skills/find-bangers/SKILL.md +2 -0
  9. package/skills/find-influencers/SKILL.md +2 -0
  10. package/skills/find-viral-tweets/SKILL.md +2 -0
  11. package/skills/follow-unfollow/SKILL.md +1 -0
  12. package/skills/for-you-feed/SKILL.md +7 -4
  13. package/skills/going-viral/SKILL.md +1 -0
  14. package/skills/grow-followers/SKILL.md +2 -0
  15. package/skills/monitor-accounts/SKILL.md +10 -9
  16. package/skills/optimize-tweets/SKILL.md +1 -0
  17. package/skills/post-tweets/SKILL.md +4 -4
  18. package/skills/run-giveaway/SKILL.md +2 -1
  19. package/skills/search-tweets/SKILL.md +3 -3
  20. package/skills/send-dms/SKILL.md +4 -3
  21. package/skills/top-replies/SKILL.md +2 -0
  22. package/skills/track-competitors/SKILL.md +6 -4
  23. package/skills/track-hashtags/SKILL.md +7 -5
  24. package/skills/track-mentions/SKILL.md +7 -5
  25. package/skills/trending-news/SKILL.md +2 -0
  26. package/skills/tweet-analytics/SKILL.md +3 -3
  27. package/skills/tweet-ideas/SKILL.md +2 -0
  28. package/skills/tweet-replies/SKILL.md +3 -1
  29. package/skills/tweet-style/SKILL.md +2 -0
  30. package/skills/tweet-webhooks/SKILL.md +8 -6
  31. package/skills/update-x-profile/SKILL.md +1 -0
  32. package/skills/user-tweets/SKILL.md +3 -3
  33. package/skills/who-liked/SKILL.md +2 -0
  34. package/skills/who-quoted/SKILL.md +2 -0
  35. package/skills/who-retweeted/SKILL.md +2 -0
  36. package/skills/write-threads/SKILL.md +1 -0
  37. package/skills/write-tweets/SKILL.md +1 -0
  38. package/skills/x-articles/SKILL.md +4 -2
  39. package/skills/x-bookmarks/SKILL.md +9 -6
  40. package/skills/x-communities/SKILL.md +2 -0
  41. package/skills/x-lists/SKILL.md +2 -0
  42. package/skills/x-spaces/SKILL.md +2 -0
  43. package/skills/x-trends/SKILL.md +2 -0
  44. package/skills/x-twitter-scraper/SKILL.md +73 -66
  45. package/skills/x-twitter-scraper/metadata.json +2 -2
  46. package/skills/x-twitter-scraper/references/api-endpoints.md +44 -26
  47. package/skills/x-twitter-scraper/references/extractions.md +4 -4
  48. package/skills/x-twitter-scraper/references/mcp-setup.md +8 -8
  49. package/skills/x-twitter-scraper/references/mcp-tools.md +33 -22
  50. package/skills/x-twitter-scraper/references/pricing.md +25 -15
  51. package/skills/x-twitter-scraper/references/python-examples.md +1 -1
  52. package/skills/x-twitter-scraper/references/types.md +61 -20
  53. package/skills/x-twitter-scraper/references/webhooks.md +12 -2
  54. package/skills/x-twitter-scraper/references/workflows.md +11 -11
@@ -7,9 +7,9 @@ The MCP server at `https://xquik.com/mcp` provides 2 structured API tools. The a
7
7
  | Tool | Description | Cost |
8
8
  |------|-------------|------|
9
9
  | `explore` | Search the API endpoint catalog (read-only, no network calls) | Free |
10
- | `xquik` | Execute API calls against your account | Varies by endpoint |
10
+ | `xquik` | Send confirmed Xquik API requests | Varies by endpoint |
11
11
 
12
- ### `explore` — Search the API Spec
12
+ ### `explore` - Search the API Spec
13
13
 
14
14
  The tool provides an in-memory `spec.endpoints` array. Filter/search it to find endpoints before calling them.
15
15
 
@@ -40,10 +40,23 @@ async () => spec.endpoints.filter(e => e.category === 'x-write');
40
40
  async () => spec.endpoints.filter(e => e.summary.toLowerCase().includes('tweet'));
41
41
  ```
42
42
 
43
- ### `xquik` — Execute API Calls
43
+ ### `xquik` - Send API Requests
44
44
 
45
45
  The tool provides `xquik.request()` with auth injected automatically. Never pass API keys.
46
46
 
47
+ ## Safety Gates
48
+
49
+ Apply these gates before using `xquik`:
50
+
51
+ | Capability | Rule |
52
+ |------------|------|
53
+ | Public writes | Show the exact tweet, reply, like, retweet, follow, unfollow, profile, or community action and wait for explicit approval. |
54
+ | Direct messages | Show sender, recipient, and message text. Never send bulk or automatic DMs. |
55
+ | Persistent resources | Create monitors and webhooks only when the user explicitly asks for ongoing delivery. Show target, event types, URL, and ongoing cost before creation. |
56
+ | Private reads | Confirm before fetching DMs, bookmarks, notifications, or home timeline. Do not forward returned private data to other tools without consent. |
57
+ | Billing or payments | Do not call checkout, top-up, or MPP payment endpoints unless the user explicitly asks and confirms the exact amount. |
58
+ | X account login | Never ask for or submit X login material. Account connection and re-authentication happen in the dashboard. |
59
+
47
60
  ```typescript
48
61
  declare const xquik: {
49
62
  request(path: string, options?: {
@@ -70,22 +83,21 @@ Use `explore` first to find endpoints, then `xquik` to call them.
70
83
  | Trending topics by region (X) | `GET /api/v1/trends?woeid=1` |
71
84
  | Trending news from 7 sources | `GET /api/v1/radar` (via `xquik` tool) |
72
85
  | Activity from monitored accounts | `GET /api/v1/events` |
73
- | Budget, plan, usage percent | `GET /api/v1/account` |
74
- | Monitor an X account | `POST /api/v1/monitors` |
75
- | Set up webhook notifications | `POST /api/v1/webhooks` |
86
+ | Credit balance, plan, monitor billing | `GET /api/v1/account` |
87
+ | Monitor an X account | `POST /api/v1/monitors` (persistent; confirmation required) |
88
+ | Set up webhook notifications | `POST /api/v1/webhooks` (persistent; confirmation required) |
76
89
  | Run a giveaway draw | `POST /api/v1/draws` |
77
- | Subscribe or manage billing | `POST /api/v1/subscribe` |
78
90
  | Compose/draft a tweet | `POST /api/v1/compose` (3-step: compose, refine, score) |
79
91
  | Link your X username | `PUT /api/v1/account/x-identity` |
80
92
  | Analyze tweet style | `POST /api/v1/styles` |
81
93
  | Get cached style | `GET /api/v1/styles/{username}` |
82
94
  | Compare two styles | `GET /api/v1/styles/compare` |
83
- | Post a tweet | `POST /api/v1/x/tweets` (requires connected account) |
84
- | Like/unlike a tweet | `POST`/`DELETE /api/v1/x/tweets/{id}/like` |
85
- | Retweet | `POST /api/v1/x/tweets/{id}/retweet` |
86
- | Follow/unfollow | `POST`/`DELETE /api/v1/x/users/{id}/follow` |
87
- | Send a DM | `POST /api/v1/x/dm/{userId}` |
88
- | Upload media | `POST /api/v1/x/media` |
95
+ | Post a tweet | `POST /api/v1/x/tweets` (confirmation required) |
96
+ | Like/unlike a tweet | `POST`/`DELETE /api/v1/x/tweets/{id}/like` (confirmation required) |
97
+ | Retweet | `POST /api/v1/x/tweets/{id}/retweet` (confirmation required) |
98
+ | Follow/unfollow | `POST`/`DELETE /api/v1/x/users/{id}/follow` (confirmation required) |
99
+ | Send a DM | `POST /api/v1/x/dm/{userId}` (confirmation required) |
100
+ | Upload media | `POST /api/v1/x/media` (confirmation required before use in a post or profile change) |
89
101
  | Open support ticket | `POST /api/v1/support/tickets` |
90
102
  | List support tickets | `GET /api/v1/support/tickets` |
91
103
  | Get user's recent tweets | `GET /api/v1/x/users/{id}/tweets` |
@@ -93,13 +105,12 @@ Use `explore` first to find endpoints, then `xquik` to call them.
93
105
  | Get user's media tweets | `GET /api/v1/x/users/{id}/media` |
94
106
  | Get tweet favoriters (who liked) | `GET /api/v1/x/tweets/{id}/favoriters` |
95
107
  | Get mutual followers | `GET /api/v1/x/users/{id}/followers-you-know` |
96
- | Get bookmarks | `GET /api/v1/x/bookmarks` |
108
+ | Get bookmarks | `GET /api/v1/x/bookmarks` (private; confirmation required) |
97
109
  | Get bookmark folders | `GET /api/v1/x/bookmarks/folders` |
98
- | Get notifications | `GET /api/v1/x/notifications` |
99
- | Get home timeline | `GET /api/v1/x/timeline` |
100
- | Get DM history | `GET /api/v1/x/dm/{userId}/history` |
110
+ | Get notifications | `GET /api/v1/x/notifications` (private; confirmation required) |
111
+ | Get home timeline | `GET /api/v1/x/timeline` (private; confirmation required) |
112
+ | Get DM history | `GET /api/v1/x/dm/{userId}/history` (private; confirmation required) |
101
113
  | Check credit balance | `GET /api/v1/credits` |
102
- | Top up credits | `POST /api/v1/credits/topup` |
103
114
 
104
115
  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.
105
116
 
@@ -107,7 +118,7 @@ Use `POST /api/v1/extractions` ONLY for bulk data that simpler endpoints cannot
107
118
 
108
119
  | Workflow | Steps |
109
120
  |----------|-------|
110
- | **Set up real-time alerts** | `POST /monitors` -> `POST /webhooks` -> `POST /webhooks/{id}/test` |
121
+ | **Set up real-time alerts** | Confirm target, event types, destination, and cost -> `POST /monitors` -> `POST /webhooks` -> `POST /webhooks/{id}/test` |
111
122
  | **Run a giveaway** | `GET /account` -> `POST /draws` |
112
123
  | **Bulk extraction** | `POST /extractions/estimate` -> `POST /extractions` -> `GET /extractions/{id}` |
113
124
  | **Compose optimized tweet** | `POST /compose` (step=compose -> refine -> score) |
@@ -124,7 +135,7 @@ Use `POST /api/v1/extractions` ONLY for bulk data that simpler endpoints cannot
124
135
  | Using `compose` when user wants to send a tweet | `POST /compose` is for drafting. Use `POST /x/tweets` to send |
125
136
  | Using `POST /x/tweets` when user wants help writing | Use the 3-step compose flow instead |
126
137
  | Falling back to web search when API call fails | Use free data already fetched (radar, styles, compose). Never discard it |
127
- | Not checking subscription before paid calls | Always attempt the call. Handle 402 by calling `POST /subscribe` for checkout URL |
138
+ | Not checking subscription before paid calls | Attempt the requested call. On 402, explain the billing issue and ask before any checkout or top-up action |
128
139
  | Passing API keys in code | Auth is injected automatically. Never include keys |
129
140
  | Using `explore` for API calls | `explore` is read-only spec search. Use `xquik` for actual API calls |
130
141
  | Looking up follow/DM by username | Follow and DM endpoints need numeric user ID. Look up via `GET /x/users/{username}` first |
@@ -142,5 +153,5 @@ These are NOT available via the MCP server:
142
153
 
143
154
  ## Cost Reference
144
155
 
145
- - **Free**: account info, compose (all steps), styles (cached lookup/save/delete/compare), drafts, radar (via `xquik` tool, all 7 sources), subscribe, API keys, X account management, support tickets, credits (balance check, top up)
146
- - **Subscription required**: tweet search, user lookup, tweet lookup, follow check, media download (first only, cached free), extractions, draws, style analysis (X API refresh), performance analysis, trends, all write actions (tweet, like, retweet, follow, DM, profile, media upload, communities)
156
+ - **Free**: account info, compose (all steps), styles (cached lookup/save/delete/compare), drafts, radar (via `xquik` tool, all 7 sources), support tickets, credits balance check, webhook management
157
+ - **Credit or subscription required**: tweet search, user lookup, tweet lookup, follow check, media download (first only, cached free), extractions, draws, active monitors, style analysis (X API refresh), performance analysis, trends, and confirmation-gated write actions (tweet, like, retweet, follow, DM, profile, media upload, communities)
@@ -6,10 +6,14 @@ Xquik is the most affordable X data API available. All metered operations deduct
6
6
 
7
7
  | | |
8
8
  |---|---|
9
- | **Base plan** | $20/month |
10
- | **Included monitors** | 1 |
11
- | **Additional monitors** | $5/month each |
12
- | **Credit value** | 1 credit = $0.00015 |
9
+ | **Starter** | $20/month, 140,000 included credits |
10
+ | **Pro** | $99/month, 770,000 included credits |
11
+ | **Business** | $199/month, 1,670,000 included credits |
12
+ | **Monitor slots** | Unlimited |
13
+ | **Active monitors** | 21 credits/hour each, about 500 credits/day |
14
+ | **PAYG/top-up credit value** | 1 credit = $0.00015 |
15
+
16
+ Subscription credits are added each billing period, and unused credits carry over. Top-up credits do not expire.
13
17
 
14
18
  ## Per-Operation Costs
15
19
 
@@ -48,7 +52,7 @@ Xquik is the most affordable X data API available. All metered operations deduct
48
52
 
49
53
  ### Write operations - 10 credits ($0.0015)
50
54
 
51
- All write actions: create/delete tweet, like, unlike, retweet, follow, unfollow, send DM, update profile/avatar/banner, upload media, community actions.
55
+ All confirmation-gated write actions: create/delete tweet, like, unlike, retweet, follow, unfollow, send DM, update profile/avatar/banner, upload media, community actions.
52
56
 
53
57
  ### Extractions & draws
54
58
 
@@ -60,21 +64,25 @@ Draws: 1 credit per participant. Extraction cost depends on the tool type:
60
64
  | 1 | Followers, following, verified followers |
61
65
  | 5 | Articles |
62
66
 
67
+ ### Active monitors
68
+
69
+ Active account and keyword monitors cost 21 credits/hour each. Events and webhook delivery are included.
70
+
63
71
  ### Free operations ($0)
64
72
 
65
- Monitors, webhooks, account status, radar (7 sources), extraction/draw history, cost estimates, tweet composition (compose, refine, score), style cache management, drafts, support tickets, API key management, X account management.
73
+ Webhooks, account status, radar (7 sources), extraction/draw history, cost estimates, tweet composition (compose, refine, score), style cache management, drafts, support tickets, and X account listing.
66
74
 
67
75
  ## Price Comparison vs Official X API
68
76
 
69
77
  | | Xquik | Official X pay-per-usage | Notes |
70
78
  |---|---|---|---|
71
- | **Access model** | **$20/month full API, plus pay-per-use options** | No subscriptions or commitments | Basic and Pro are legacy package names |
79
+ | **Access model** | **Starter/Pro/Business subscriptions, credit top-ups, and MPP** | No subscriptions or commitments | Basic and Pro are legacy package names |
72
80
  | **Cost per post read** | **$0.00015** | $0.005 per resource | Xquik is about 33x cheaper |
73
81
  | **Cost per user lookup** | **$0.00015** | $0.010 per resource | Xquik is about 67x cheaper |
74
82
  | **Cost per trend read** | **$0.00045** | $0.010 per resource | Xquik is about 22x cheaper |
75
83
  | **Write actions** | **$0.0015** | $0.015 content or interaction create; $0.200 content create with URL | Xquik is 10x cheaper for matching $0.015 write classes |
76
84
  | **Bulk extraction** | **$0.00015/result** | Charged per returned resource | Built-in extraction jobs are included with Xquik |
77
- | **Monitoring + webhooks** | **Free** | No direct monitor product in pricing table | Real-time delivery is included |
85
+ | **Monitoring + webhooks** | Active monitors are metered; webhooks included | No direct monitor product in pricing table | Real-time delivery is included |
78
86
  | **Giveaway draws** | **$0.00015/entry** | No comparable draw product | Draw engine is included |
79
87
 
80
88
  Source: [official X API pricing](https://docs.x.com/x-api/getting-started/pricing), which lists current pay-per-usage read and write rates.
@@ -83,9 +91,9 @@ Source: [official X API pricing](https://docs.x.com/x-api/getting-started/pricin
83
91
 
84
92
  Two options without a monthly subscription:
85
93
 
86
- **Credits**: Top up credits via `POST /credits/topup` ($10 minimum). 1 credit = $0.00015. Works with all 113 endpoints.
94
+ **Credits**: Start a credit top-up checkout only after explicit confirmation. 1 top-up credit = $0.00015. Works with all supported endpoints.
87
95
 
88
- **MPP**: 32 X-API endpoints accept anonymous on-chain payments. No account needed.
96
+ **MPP**: 32 X-API endpoints accept optional per-call payments. Show the exact amount and get explicit confirmation before starting any payment flow.
89
97
 
90
98
  | Endpoint | Price | Unit |
91
99
  |----------|-------|------|
@@ -122,14 +130,16 @@ Two options without a monthly subscription:
122
130
  | `GET /x/users/{id}/mentions` | $0.00015 | per tweet |
123
131
  | `GET /x/users/{id}/verified-followers` | $0.00015 | per user |
124
132
 
125
- SDK: `npm i mppx viem` (TypeScript). Handles the 402 challenge/credential flow automatically.
133
+ SDK: `npm i mppx@0.6.15 viem@2.48.8` (TypeScript). Handles the 402 payment challenge flow.
126
134
 
127
135
  ## Credits
128
136
 
129
- Prepaid credits for metered operations. 1 credit = $0.00015. Top up via `POST /credits/topup` ($10 minimum).
137
+ Prepaid credits for metered operations. Top-up credits cost $0.00015 each. Start top-up checkout via `POST /credits/topup` only after explicit confirmation ($10 minimum).
138
+
139
+ Check balance: `GET /credits` - returns `balance`, `lifetimePurchased`, `lifetimeUsed`, and auto-top-up fields.
130
140
 
131
- Check balance: `GET /credits` - returns `balance`, `lifetimePurchased`, `lifetimeUsed`.
141
+ ## Credit Top-Ups
132
142
 
133
- ## Extra Usage
143
+ Use `POST /credits/topup` to create a hosted checkout session, `GET /credits/topup/status?session_id=...` to poll checkout completion, and `POST /credits/quick-topup` to charge a saved payment method after explicit confirmation of the exact amount. Quick top-up returns `charged`, `no_payment_method`, or `requires_action`.
134
144
 
135
- Enable from dashboard to continue metered calls beyond included allowance. Tiered spending limits: $5 -> $7 -> $10 -> $15 -> $25 (increases with each paid overage invoice).
145
+ Automatic top-up can be configured from the dashboard. `GET /credits` and `GET /account` expose whether it is enabled, the dollar amount, and the trigger threshold.
@@ -51,7 +51,7 @@ estimate = xquik_fetch("/extractions/estimate", method="POST", json_body={
51
51
  })
52
52
 
53
53
  if not estimate["allowed"]:
54
- print(f"Would exceed quota: {estimate['projectedPercent']}%")
54
+ print(f"Need {estimate['creditsRequired']} credits; available {estimate['creditsAvailable']}")
55
55
  exit()
56
56
 
57
57
  # Step 2: Create job
@@ -24,29 +24,55 @@ Copy-pasteable TypeScript types for all Xquik API objects.
24
24
 
25
25
  interface Account {
26
26
  plan: "active" | "inactive";
27
- pricingVersion: number;
28
27
  monitorsAllowed: number;
29
28
  monitorsUsed: number;
30
- currentPeriod?: {
31
- start: string;
32
- end: string;
33
- usagePercent: number;
29
+ monitorBilling: {
30
+ activeDailyEstimate: string;
31
+ activeHourlyBurn: string;
32
+ creditsPerActiveMonitorDay: string;
33
+ creditsPerActiveMonitorHour: string;
34
+ eventsIncluded: boolean;
35
+ instantCheckIntervalSeconds: number;
36
+ unlimitedSlots: boolean;
34
37
  };
38
+ creditInfo?: {
39
+ balance: string;
40
+ lifetimePurchased: string;
41
+ lifetimeUsed: string;
42
+ autoTopupEnabled: boolean;
43
+ autoTopupAmountDollars: number;
44
+ autoTopupThreshold: string;
45
+ };
46
+ xUsername?: string;
35
47
  }
36
48
 
37
49
  // ─── Credits ────────────────────────────────────────────
38
50
 
39
51
  interface CreditBalance {
40
- balance: number; // Current credit balance
41
- lifetimePurchased: number; // Total credits purchased
42
- lifetimeUsed: number; // Total credits consumed
43
- autoTopUp: boolean; // Whether auto top-up is enabled
52
+ balance: string; // Current credit balance, bigint string
53
+ lifetimePurchased: string; // Total credits purchased, bigint string
54
+ lifetimeUsed: string; // Total credits consumed, bigint string
55
+ autoTopupEnabled: boolean; // Whether auto top-up is enabled
56
+ autoTopupAmountDollars: number; // Dollar amount charged by auto top-up
57
+ autoTopupThreshold: string; // Trigger threshold, bigint string
44
58
  }
45
59
 
46
60
  interface CreditTopUpResponse {
47
61
  url: string; // Checkout URL
48
62
  }
49
63
 
64
+ type CreditQuickTopUpResponse =
65
+ | {
66
+ outcome: "charged";
67
+ credits: string; // Credits added, bigint string
68
+ balance: string; // New balance, bigint string
69
+ }
70
+ | { outcome: "no_payment_method" }
71
+ | {
72
+ outcome: "requires_action";
73
+ clientSecret: string; // Complete required cardholder action
74
+ };
75
+
50
76
  // ─── API Keys ────────────────────────────────────────────
51
77
 
52
78
  interface ApiKeyCreated {
@@ -279,10 +305,11 @@ interface ExtractionList {
279
305
 
280
306
  interface ExtractionEstimate {
281
307
  allowed: boolean;
308
+ creditsAvailable: string;
309
+ creditsRequired: string;
282
310
  source: "replyCount" | "retweetCount" | "quoteCount" | "followers" | "unknown";
283
311
  estimatedResults: number;
284
- usagePercent: number;
285
- projectedPercent: number;
312
+ resolvedXUserId?: string;
286
313
  error?: string;
287
314
  }
288
315
 
@@ -811,9 +838,10 @@ interface McpExtractionJob {
811
838
  interface McpExtractionEstimate {
812
839
  allowed?: boolean; // Whether the extraction is allowed within budget
813
840
  estimatedResults?: number; // Estimated number of results
814
- projectedPercent?: number; // Projected usage percent after extraction
815
- usagePercent?: number; // Current usage percent of monthly quota
841
+ creditsRequired?: string; // Required credits, bigint string
842
+ creditsAvailable?: string; // Available credits, bigint string
816
843
  source?: string; // Data source used for estimation
844
+ resolvedXUserId?: string; // Resolved user ID for username-based estimates
817
845
  error?: string; // Error message if estimation failed
818
846
  }
819
847
 
@@ -862,14 +890,27 @@ interface McpDrawDetails {
862
890
  // ─── MCP: get-account ───────────────────────────────────
863
891
 
864
892
  interface McpAccount {
865
- plan: string; // Current plan name (free or subscriber)
866
- monitorsAllowed: number; // Maximum monitors allowed on current plan
893
+ plan: "active" | "inactive";
894
+ monitorsAllowed: number; // Deprecated; monitor slots are unlimited
867
895
  monitorsUsed: number; // Number of active monitors
868
- currentPeriod?: { // Current billing period (present only with active subscription)
869
- start: string; // ISO 8601 period start date
870
- end: string; // ISO 8601 period end date
871
- usagePercent: number; // Percent of monthly quota consumed
896
+ monitorBilling: {
897
+ activeDailyEstimate: string;
898
+ activeHourlyBurn: string;
899
+ creditsPerActiveMonitorDay: string;
900
+ creditsPerActiveMonitorHour: string;
901
+ eventsIncluded: boolean;
902
+ instantCheckIntervalSeconds: number;
903
+ unlimitedSlots: boolean;
904
+ };
905
+ creditInfo?: {
906
+ balance: string;
907
+ lifetimePurchased: string;
908
+ lifetimeUsed: string;
909
+ autoTopupEnabled: boolean;
910
+ autoTopupAmountDollars: number;
911
+ autoTopupThreshold: string;
872
912
  };
913
+ xUsername?: string;
873
914
  }
874
915
 
875
916
  // ─── MCP: get-trends ────────────────────────────────────
@@ -955,7 +996,7 @@ interface ConnectedXAccount {
955
996
  }
956
997
 
957
998
  // Connecting an X account is done by the user in the Xquik dashboard,
958
- // not through this skill. The skill never handles X login credentials.
999
+ // not through this skill. The skill never handles X login material.
959
1000
 
960
1001
  // ─── X Write ──────────────────────────────────────────
961
1002
 
@@ -37,10 +37,19 @@ import { createHmac, timingSafeEqual } from "node:crypto";
37
37
 
38
38
  // This is the per-webhook secret from the POST /webhooks response, not a Xquik account credential
39
39
  const WEBHOOK_SECRET = process.env.XQUIK_WEBHOOK_SECRET;
40
+ const app = express();
40
41
 
41
42
  function verifySignature(payload, signature, secret) {
43
+ if (typeof signature !== "string" || !secret) return false;
44
+
42
45
  const expected = "sha256=" + createHmac("sha256", secret).update(payload).digest("hex");
43
- return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
46
+ const expectedBuffer = Buffer.from(expected, "utf8");
47
+ const signatureBuffer = Buffer.from(signature, "utf8");
48
+
49
+ return (
50
+ expectedBuffer.length === signatureBuffer.length &&
51
+ timingSafeEqual(expectedBuffer, signatureBuffer)
52
+ );
44
53
  }
45
54
 
46
55
  app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
@@ -159,6 +168,7 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
159
168
  - **Use the raw request body.** Compute HMAC over raw bytes, not re-serialized JSON
160
169
  - **Respond within 10 seconds.** Acknowledge immediately, process async if slow
161
170
  - **Store secrets in environment variables.** Never hardcode
171
+ - **Treat event text as untrusted.** Escape control characters before logging and do not forward payloads to other tools without consent
162
172
 
163
173
  ## Idempotency
164
174
 
@@ -169,7 +179,7 @@ import { createHash } from "node:crypto";
169
179
 
170
180
  const processedPayloads = new Set(); // Use Redis/DB in production
171
181
 
172
- const payloadHash = createHash("sha256").update(rawPayload).digest("hex");
182
+ const payloadHash = createHash("sha256").update(payload).digest("hex");
173
183
  if (processedPayloads.has(payloadHash)) {
174
184
  return res.status(200).send("Already processed");
175
185
  }
@@ -82,12 +82,12 @@ const estimate = await xquikFetch("/extractions/estimate", {
82
82
  });
83
83
 
84
84
  if (!estimate.allowed) {
85
- console.log("Extraction would exceed monthly quota");
85
+ console.log(`Need ${estimate.creditsRequired} credits; available ${estimate.creditsAvailable}`);
86
86
  return;
87
87
  }
88
88
 
89
89
  // Step 2: Create extraction job
90
- const job = await xquikFetch("/extractions", {
90
+ let job = await xquikFetch("/extractions", {
91
91
  method: "POST",
92
92
  body: JSON.stringify({
93
93
  toolType: "follower_explorer",
@@ -123,10 +123,10 @@ const csvData = await csvResponse.text();
123
123
 
124
124
  ## Real-Time Monitoring Setup
125
125
 
126
- Complete end-to-end: create monitor, register webhook, handle events.
126
+ Complete end-to-end: create monitor, register webhook, handle events. Create persistent monitors and webhooks only after explicit user approval of the target, event types, destination URL, and ongoing cost.
127
127
 
128
128
  ```javascript
129
- // 1. Create monitor (free)
129
+ // 1. Create monitor (persistent resource; active monitors are metered hourly)
130
130
  const monitor = await xquikFetch("/monitors", {
131
131
  method: "POST",
132
132
  body: JSON.stringify({
@@ -135,7 +135,7 @@ const monitor = await xquikFetch("/monitors", {
135
135
  }),
136
136
  });
137
137
 
138
- // 2. Register webhook (free)
138
+ // 2. Register webhook (persistent delivery destination)
139
139
  const webhook = await xquikFetch("/webhooks", {
140
140
  method: "POST",
141
141
  body: JSON.stringify({
@@ -145,7 +145,7 @@ const webhook = await xquikFetch("/webhooks", {
145
145
  });
146
146
  // IMPORTANT: Save webhook.secret. It is shown only once!
147
147
 
148
- // 3. Poll events (alternative to webhooks, free)
148
+ // 3. Poll events (alternative to webhooks)
149
149
  const events = await xquikFetch("/events?monitorId=7&limit=50");
150
150
  ```
151
151
 
@@ -156,7 +156,7 @@ Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `webhoo
156
156
  | Goal | Endpoint | Cost |
157
157
  |------|----------|------|
158
158
  | **Get a single tweet** by ID/URL | `GET /x/tweets/{id}` | 1 credit |
159
- | **Get an X Article** by tweet ID | `GET /x/articles/{id}` | 7 credits |
159
+ | **Get an X Article** by tweet ID | `GET /x/articles/{id}` | 5 credits |
160
160
  | **Search tweets** by keyword/hashtag | `GET /x/tweets/search?q=...` | 1 credit/tweet |
161
161
  | **Get a user profile** | `GET /x/users/{username}` | 1 credit |
162
162
  | **Get user's recent tweets** | `GET /x/users/{id}/tweets` | 1 credit/tweet |
@@ -164,7 +164,7 @@ Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `webhoo
164
164
  | **Get user's media tweets** | `GET /x/users/{id}/media` | 1 credit/result |
165
165
  | **Get tweet favoriters** | `GET /x/tweets/{id}/favoriters` | 1 credit/result |
166
166
  | **Get mutual followers** | `GET /x/users/{id}/followers-you-know` | 1 credit/result |
167
- | **Check follow relationship** | `GET /x/followers/check?source=A&target=B` | 7 credits |
167
+ | **Check follow relationship** | `GET /x/followers/check?source=A&target=B` | 5 credits |
168
168
  | **Get trending topics** | `GET /trends?woeid=1` | 3 credits |
169
169
  | **Get radar (trending news)** | `GET /radar?source=hacker_news` | Free |
170
170
  | **Get bookmarks** | `GET /x/bookmarks` | 1 credit/result |
@@ -172,14 +172,14 @@ Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `webhoo
172
172
  | **Get notifications** | `GET /x/notifications` | 1 credit/result |
173
173
  | **Get home timeline** | `GET /x/timeline` | 1 credit/result |
174
174
  | **Get DM history** | `GET /x/dm/{userId}/history` | 1 credit/result |
175
- | **Monitor an X account** | `POST /monitors` | Free |
175
+ | **Monitor an X account** | `POST /monitors` | Active monitors are metered hourly |
176
176
  | **Poll for events** | `GET /events` | Free |
177
- | **Receive events via webhook** | `POST /webhooks` | Free |
177
+ | **Receive events via webhook** | `POST /webhooks` | Free; confirmation required for destination URL |
178
178
  | **Run a giveaway draw** | `POST /draws` | 1 credit/entry |
179
179
  | **Download tweet media** | `POST /x/media/download` | 1 credit/item |
180
180
  | **Extract bulk data** | `POST /extractions` | 1-5 credits/result |
181
181
  | **Check credits** | `GET /credits` | Free |
182
- | **Top up credits** | `POST /credits/topup` | Free |
182
+ | **Top up credits** | `POST /credits/topup` | Exact amount confirmation required |
183
183
  | **Compose a tweet** | `POST /compose` | Free |
184
184
  | **Post a tweet** | `POST /x/tweets` | 10 credits |
185
185
  | **Like / Unlike a tweet** | `POST` / `DELETE /x/tweets/{id}/like` | 10 credits |