x-developer 2.4.7 → 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.
- package/README.md +33 -31
- package/openclaw.plugin.json +2 -2
- package/package.json +4 -4
- package/skills/check-mutuals/SKILL.md +2 -0
- package/skills/clean-followers/SKILL.md +2 -0
- package/skills/export-tweets-csv/SKILL.md +2 -0
- package/skills/extract-followers/SKILL.md +3 -1
- package/skills/find-bangers/SKILL.md +2 -0
- package/skills/find-influencers/SKILL.md +2 -0
- package/skills/find-viral-tweets/SKILL.md +2 -0
- package/skills/follow-unfollow/SKILL.md +1 -0
- package/skills/for-you-feed/SKILL.md +7 -4
- package/skills/going-viral/SKILL.md +1 -0
- package/skills/grow-followers/SKILL.md +2 -0
- package/skills/monitor-accounts/SKILL.md +10 -9
- package/skills/optimize-tweets/SKILL.md +1 -0
- package/skills/post-tweets/SKILL.md +5 -5
- package/skills/run-giveaway/SKILL.md +2 -1
- package/skills/search-tweets/SKILL.md +3 -3
- package/skills/send-dms/SKILL.md +4 -3
- package/skills/top-replies/SKILL.md +2 -0
- package/skills/track-competitors/SKILL.md +6 -4
- package/skills/track-hashtags/SKILL.md +7 -5
- package/skills/track-mentions/SKILL.md +7 -5
- package/skills/trending-news/SKILL.md +2 -0
- package/skills/tweet-analytics/SKILL.md +4 -4
- package/skills/tweet-ideas/SKILL.md +2 -0
- package/skills/tweet-replies/SKILL.md +3 -1
- package/skills/tweet-style/SKILL.md +2 -0
- package/skills/tweet-webhooks/SKILL.md +8 -6
- package/skills/update-x-profile/SKILL.md +1 -0
- package/skills/user-tweets/SKILL.md +3 -3
- package/skills/who-liked/SKILL.md +2 -0
- package/skills/who-quoted/SKILL.md +2 -0
- package/skills/who-retweeted/SKILL.md +2 -0
- package/skills/write-threads/SKILL.md +1 -0
- package/skills/write-tweets/SKILL.md +1 -0
- package/skills/x-articles/SKILL.md +4 -2
- package/skills/x-bookmarks/SKILL.md +9 -6
- package/skills/x-communities/SKILL.md +2 -0
- package/skills/x-lists/SKILL.md +2 -0
- package/skills/x-spaces/SKILL.md +2 -0
- package/skills/x-trends/SKILL.md +2 -0
- package/skills/x-twitter-scraper/SKILL.md +73 -66
- package/skills/x-twitter-scraper/metadata.json +2 -2
- package/skills/x-twitter-scraper/references/api-endpoints.md +52 -26
- package/skills/x-twitter-scraper/references/extractions.md +4 -4
- package/skills/x-twitter-scraper/references/mcp-setup.md +8 -8
- package/skills/x-twitter-scraper/references/mcp-tools.md +33 -22
- package/skills/x-twitter-scraper/references/pricing.md +26 -16
- package/skills/x-twitter-scraper/references/python-examples.md +1 -1
- package/skills/x-twitter-scraper/references/types.md +61 -20
- package/skills/x-twitter-scraper/references/webhooks.md +12 -2
- 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` |
|
|
10
|
+
| `xquik` | Send confirmed Xquik API requests | Varies by endpoint |
|
|
11
11
|
|
|
12
|
-
### `explore`
|
|
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`
|
|
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
|
-
|
|
|
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` (
|
|
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 |
|
|
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),
|
|
146
|
-
- **
|
|
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
|
-
| **
|
|
10
|
-
| **
|
|
11
|
-
| **
|
|
12
|
-
| **
|
|
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
|
|
|
@@ -39,7 +43,7 @@ Xquik is the most affordable X data API available. All metered operations deduct
|
|
|
39
43
|
|-----------|------|
|
|
40
44
|
| Trends | per call |
|
|
41
45
|
|
|
42
|
-
### Read operations -
|
|
46
|
+
### Read operations - 5 credits ($0.00075)
|
|
43
47
|
|
|
44
48
|
| Operation | Unit |
|
|
45
49
|
|-----------|------|
|
|
@@ -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
|
-
|
|
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** |
|
|
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** |
|
|
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**:
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
141
|
+
## Credit Top-Ups
|
|
132
142
|
|
|
133
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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:
|
|
41
|
-
lifetimePurchased:
|
|
42
|
-
lifetimeUsed:
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
815
|
-
|
|
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:
|
|
866
|
-
monitorsAllowed: number; //
|
|
893
|
+
plan: "active" | "inactive";
|
|
894
|
+
monitorsAllowed: number; // Deprecated; monitor slots are unlimited
|
|
867
895
|
monitorsUsed: number; // Number of active monitors
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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
|
|
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}` |
|
|
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` |
|
|
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` |
|
|
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` |
|
|
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 |
|