Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
TweetClaw
https://github.com/xquik-dev/tweetclaw
Admin
OpenClaw plugin for safe Xquik X/Twitter automation with endpoint discovery, explicit approval
...
Tokens:
35,562
Snippets:
202
Trust Score:
7.5
Update:
4 hours ago
Context
Skills
Chat
Benchmark
85.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# TweetClaw TweetClaw (`@xquik/tweetclaw`) is an [OpenClaw](https://github.com/openclaw/openclaw) plugin that brings full X/Twitter automation directly into an AI agent session. It connects to the [Xquik](https://xquik.com) API platform to expose 99 agent-callable endpoints across 9 categories—tweet reads, searches, writes, user lookups, monitors, webhooks, bulk extractions, giveaway draws, and media handling—all through two structured agent tools: a free, offline endpoint catalog browser (`explore`) and a live endpoint invoker (`tweetclaw`). Credentials are injected by the plugin runtime; the agent never handles raw API keys, X session tokens, or passwords. The plugin registers with the OpenClaw SDK's `definePluginEntry`, supports three credential modes (API key, MPP pay-per-use, or unconfigured explore-only), attaches a `before_tool_call` approval hook for write and paid operations, and optionally polls the Xquik events endpoint every 60 seconds to surface monitor alerts into the chat. Pricing runs through Xquik's credit system at $0.00015 per read, $0.0015 per write, and $0.00015 per extraction result—approximately 33× cheaper than the official X API for post reads. --- ## Installation and Configuration Install the plugin into an OpenClaw environment and configure one of the three credential modes. ```bash # Install openclaw plugins install @xquik/tweetclaw # Option A – API key (full access: reads + writes + monitors) openclaw config set plugins.entries.tweetclaw.config.apiKey "$XQUIK_API_KEY" # Option B – MPP signing key (32 read-only endpoints, no Xquik account needed) npm i mppx viem openclaw config set plugins.entries.tweetclaw.config.tempoSigningKey "$MPP_SIGNING_KEY" # Optional: allow both tools in your tool profile openclaw config set tools.alsoAllow '["explore", "tweetclaw"]' # Optional: configure polling interval (default 60 s) openclaw config set plugins.entries.tweetclaw.config.pollingInterval 30 # Verify registration openclaw plugins inspect tweetclaw --runtime openclaw skills info tweetclaw ``` --- ## Plugin Entry – `definePluginEntry` / `register` The `register` function is the plugin's main entry point. It resolves credentials, registers the `explore` and `tweetclaw` tools, registers the `/xstatus` and `/xtrends` slash commands, attaches the write-approval hook, and optionally starts the event poller. This runs once on plugin load; you do not call it directly. ```typescript import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry'; import { register } from '@xquik/tweetclaw'; // Plugin config schema accepted by OpenClaw: const CONFIG_SCHEMA = { additionalProperties: false, properties: { apiKey: { type: 'string', minLength: 1 }, baseUrl: { type: 'string', default: 'https://xquik.com' }, pollingEnabled: { type: 'boolean', default: true }, pollingInterval: { type: 'number', default: 60 }, tempoSigningKey: { type: 'string', minLength: 1 }, }, type: 'object', }; // Exported plugin entry consumed by OpenClaw loader: const plugin = definePluginEntry({ configSchema: CONFIG_SCHEMA, description: 'Structured X/Twitter automation through Xquik', id: 'tweetclaw', name: 'TweetClaw', register, }); export default plugin; // Credential resolution (internal – shown for reference): // 'api-key' → full access via XQUIK_API_KEY // 'mpp' → 32 read-only endpoints via MPP signing key // 'none' → explore-only; live calls return setup guidance ``` --- ## Tool: `explore` – Offline Endpoint Catalog Search `explore` searches the bundled in-memory API spec with no network calls. Use it to discover available endpoints, their parameters, cost, and response shape before calling `tweetclaw`. ```typescript // Parameters accepted by the explore tool: interface ExploreParams { query?: string; // keyword search across summaries, paths, params, response shapes category?: string; // account | composition | credits | extraction | media | monitoring | twitter | x-accounts | x-write method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; path?: string; // exact or partial path match, e.g. '/api/v1/x/tweets' free?: boolean; // true = free endpoints only mpp?: boolean; // true = MPP-eligible endpoints only limit?: number; // 1–100, default 25 } // Example agent usage – discover tweet write endpoints: // Tool: explore // Params: { "category": "x-write", "method": "POST" } // Returns: // [ // { // method: 'POST', path: '/api/v1/x/tweets', // summary: 'Create tweet', // category: 'x-write', free: false, // parameters: [ // { name: 'account', in: 'body', required: true, type: 'string' }, // { name: 'text', in: 'body', required: true, type: 'string' }, // { name: 'reply_to_tweet_id', in: 'body', required: false, type: 'string' }, // { name: 'media_ids', in: 'body', required: false, type: 'array' }, // ], // responseShape: '{ tweetId, success: true }', // }, // { method: 'POST', path: '/api/v1/x/tweets/:id/like', summary: 'Like tweet', ... }, // { method: 'POST', path: '/api/v1/x/users/:id/follow', summary: 'Follow user', ... }, // ] // Discover free composition endpoints: // Tool: explore // Params: { "category": "composition", "free": true } // Find MPP-eligible read endpoints (no account needed): // Tool: explore // Params: { "mpp": true, "method": "GET" } ``` --- ## Tool: `tweetclaw` – Live Endpoint Invoker `tweetclaw` invokes any endpoint from the catalog. Auth is injected automatically. All non-GET requests and sensitive GET paths trigger an OpenClaw approval prompt before execution. ```typescript // Parameters accepted by the tweetclaw tool: interface TweetclawParams { path: string; // required – /api/v1/... from catalog method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; // default 'GET' query?: Record<string, string | number | boolean>; body?: unknown; // JSON body for POST/PATCH/PUT } // ── POST a tweet ────────────────────────────────────────────────────────────── // Tool: tweetclaw // Params: { "path": "/api/v1/x/tweets", "method": "POST", "body": { "account": "@myaccount", "text": "Hello from TweetClaw!" } } // Response: { "tweetId": "1234567890", "success": true } // ── Reply to a tweet ────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets", "method": "POST", "body": { "account": "@myaccount", "text": "Great thread!", "reply_to_tweet_id": "9876543210" } } // ── Search tweets ───────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/search", "method": "GET", "query": { "q": "AI agents", "limit": 50 } } // Response: { "tweets": [{ "id": "...", "text": "...", "author": {...}, "likeCount": 42 }], "total": 50 } // ── Like a tweet ────────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/like", "method": "POST", "body": { "account": "@myaccount" } } // Response: { "success": true } // ── Follow a user (requires user ID lookup first) ───────────────────────────── // Step 1: look up user ID { "path": "/api/v1/x/users/elonmusk", "method": "GET" } // Response: { "id": "44196397", "username": "elonmusk", "name": "Elon Musk", "followers": 200000000 } // Step 2: follow { "path": "/api/v1/x/users/44196397/follow", "method": "POST", "body": { "account": "@myaccount" } } // ── Send a DM ───────────────────────────────────────────────────────────────── { "path": "/api/v1/x/dm/44196397", "method": "POST", "body": { "account": "@myaccount", "text": "Hey, let's collaborate!" } } // Response: { "messageId": "...", "success": true } // ── Upload media then tweet with image ──────────────────────────────────────── // Step 1: upload from URL { "path": "/api/v1/x/media", "method": "POST", "body": { "account": "@myaccount", "url": "https://example.com/photo.jpg" } } // Response: { "mediaId": "abc123", "success": true } // Step 2: tweet with media { "path": "/api/v1/x/tweets", "method": "POST", "body": { "account": "@myaccount", "text": "Check this out!", "media_ids": ["abc123"] } } ``` --- ## API: Account & Credits Retrieve account status and credit balance. Both endpoints are free and require no credits. ```typescript // ── Get account info ────────────────────────────────────────────────────────── // Tool: tweetclaw // Params: { "path": "/api/v1/account", "method": "GET" } // Response: // { "email": "user@example.com", "locale": "en", "xUsername": "myaccount", // "subscription": { "isActive": true, "plan": "pro" }, // "usage": { "percent": 42, "remaining": 5800 } } // ── Get credit balance ──────────────────────────────────────────────────────── { "path": "/api/v1/credits", "method": "GET" } // Response: // { "auto_topup_enabled": false, "balance": 8500, // "lifetime_purchased": 10000, "lifetime_used": 1500 } // ── List connected X accounts ──────────────────────────────────────────────── { "path": "/api/v1/x/accounts", "method": "GET" } // Response: // { "accounts": [{ "id": "acc_01", "xUserId": "44196397", // "xUsername": "myaccount", "status": "active", "createdAt": "..." }] } ``` --- ## API: Twitter Reads Fetch tweets, users, threads, timelines, and community data. Each read costs 1 credit ($0.00015). Trend reads cost 3 credits. Follow checks cost 5 credits. ```typescript // ── Look up a single tweet ──────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890", "method": "GET" } // Response: { "tweet": { "id": "1234567890", "text": "...", "likeCount": 120, // "retweetCount": 30, "replyCount": 5, "viewCount": 5000 }, "author": {...} } // ── Get multiple tweets by IDs ──────────────────────────────────────────────── { "path": "/api/v1/x/tweets", "method": "GET", "query": { "ids": "111,222,333" } } // ── Get user's recent tweets ────────────────────────────────────────────────── { "path": "/api/v1/x/users/44196397/tweets", "method": "GET", "query": { "includeReplies": false, "pageSize": 20 } } // Response: { "tweets": [...], "has_more": true, "next_cursor": "cursor_abc" } // ── Get tweet thread ────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/thread", "method": "GET" } // ── Get replies to a tweet ──────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/replies", "method": "GET", "query": { "sinceTime": 1700000000 } } // ── Get quote tweets ────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/quotes", "method": "GET" } // ── Get users who liked a tweet ─────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/favoriters", "method": "GET" } // Response: { "users": [...], "has_more": true, "next_cursor": "..." } // ── Get users who retweeted ─────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/retweeters", "method": "GET" } // ── Get user followers ──────────────────────────────────────────────────────── { "path": "/api/v1/x/users/44196397/followers", "method": "GET", "query": { "pageSize": 200, "cursor": "cursor_xyz" } } // ── Check follow relationship ───────────────────────────────────────────────── { "path": "/api/v1/x/followers/check", "method": "GET", "query": { "source": "user_a", "target": "user_b" } } // Response: { "isFollowing": true, "isFollowedBy": false, "sourceUsername": "user_a", "targetUsername": "user_b" } // ── Get trending topics on X ────────────────────────────────────────────────── { "path": "/api/v1/x/trends", "method": "GET", "query": { "woeid": 1, "count": 10 } } // Response: { "trends": [{ "name": "#AI", "query": "#AI", "rank": 1 }], "count": 10 } // ── Get X Article content ───────────────────────────────────────────────────── { "path": "/api/v1/x/articles/1234567890", "method": "GET" } // Response: { "article": { "title": "...", "previewText": "...", "contents": [...], // "likeCount": 500, "viewCount": 20000 }, "author": {...} } // ── Get bookmarks (requires explicit user request) ──────────────────────────── { "path": "/api/v1/x/bookmarks", "method": "GET", "query": { "cursor": "" } } // ── Get home timeline (requires explicit user request) ──────────────────────── { "path": "/api/v1/x/timeline", "method": "GET" } ``` --- ## API: X Write Actions All write operations cost 10 credits ($0.0015) and require an OpenClaw approval prompt. Always pass the `account` parameter with the X username (with or without `@`). ```typescript // ── Delete a tweet ──────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890", "method": "DELETE", "body": { "account": "@myaccount" } } // ── Unlike a tweet ──────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/like", "method": "DELETE", "body": { "account": "@myaccount" } } // ── Retweet ─────────────────────────────────────────────────────────────────── { "path": "/api/v1/x/tweets/1234567890/retweet", "method": "POST", "body": { "account": "@myaccount" } } // ── Unfollow ────────────────────────────────────────────────────────────────── { "path": "/api/v1/x/users/44196397/follow", "method": "DELETE", "body": { "account": "@myaccount" } } // ── Remove a follower ───────────────────────────────────────────────────────── { "path": "/api/v1/x/users/44196397/remove-follower", "method": "POST", "body": { "account": "@myaccount" } } // ── Update profile ──────────────────────────────────────────────────────────── { "path": "/api/v1/x/profile", "method": "PATCH", "body": { "account": "@myaccount", "name": "My New Name", "description": "Building cool stuff", "location": "SF", "url": "https://mysite.com" } } // ── Update avatar from URL ──────────────────────────────────────────────────── { "path": "/api/v1/x/profile/avatar", "method": "PATCH", "body": { "account": "@myaccount", "url": "https://example.com/avatar.png" } } // ── Create a community ──────────────────────────────────────────────────────── { "path": "/api/v1/x/communities", "method": "POST", "body": { "account": "@myaccount", "name": "AI Builders", "description": "..." } } // Response: { "communityId": "...", "success": true } // ── Join / leave a community ────────────────────────────────────────────────── { "path": "/api/v1/x/communities/comm123/join", "method": "POST", "body": { "account": "@myaccount" } } // Response: { "communityId": "comm123", "communityName": "AI Builders", "success": true } ``` --- ## API: Composition (Free) Compose, refine, and score tweets using X algorithm data. Save and manage drafts. All endpoints are free. ```typescript // ── Compose a tweet (step 1 of 3) ──────────────────────────────────────────── { "path": "/api/v1/compose", "method": "POST", "body": { "step": "compose", "topic": "AI agent automation", "goal": "engagement", "styleUsername": "myaccount" } } // Response: { "contentRules": [...], "scorerWeights": {...}, "followUpQuestions": [...] } // ── Refine a draft (step 2) ─────────────────────────────────────────────────── { "path": "/api/v1/compose", "method": "POST", "body": { "step": "refine", "topic": "AI agent automation", "tone": "casual", "callToAction": "Reply with your thoughts", "mediaType": "none", "additionalContext": "https://mysite.com/blog" } } // ── Score a draft (step 3) ──────────────────────────────────────────────────── { "path": "/api/v1/compose", "method": "POST", "body": { "step": "score", "draft": "AI agents are changing how we work. Here's how...", "hasLink": false, "hasMedia": false } } // ── Save a draft ────────────────────────────────────────────────────────────── { "path": "/api/v1/drafts", "method": "POST", "body": { "text": "Draft tweet text...", "topic": "AI automation", "goal": "engagement" } } // Response: { "id": "draft_01", "text": "...", "topic": "AI automation", "createdAt": "..." } // ── List drafts ─────────────────────────────────────────────────────────────── { "path": "/api/v1/drafts", "method": "GET", "query": { "limit": 10 } } // ── Delete a draft ──────────────────────────────────────────────────────────── { "path": "/api/v1/drafts/draft_01", "method": "DELETE" } // ── Analyze a writing style ─────────────────────────────────────────────────── { "path": "/api/v1/styles", "method": "POST", "body": { "username": "paulg" } } // Response: { "xUsername": "paulg", "tweetCount": 200, "fetchedAt": "...", "tweets": [...] } // ── Compare two writing styles ──────────────────────────────────────────────── { "path": "/api/v1/styles/compare", "method": "GET", "query": { "username1": "paulg", "username2": "naval" } } // ── Get curated trending radar topics ──────────────────────────────────────── { "path": "/api/v1/radar", "method": "GET", "query": { "category": "tech", "hours": 6, "limit": 20, "region": "US" } } // Response: { "items": [{ "title": "...", "url": "...", "score": 98, "source": "hacker_news" }], // "hasMore": false, "nextCursor": null } ``` --- ## API: Monitoring & Webhooks (Free) Create account monitors and webhooks, and poll for events. Monitor creation and webhooks are free; keyword monitors cost 21 credits/hour while active. ```typescript // ── Create an account monitor ───────────────────────────────────────────────── { "path": "/api/v1/monitors", "method": "POST", "body": { "username": "elonmusk", "eventTypes": ["tweet.new", "tweet.reply", "tweet.retweet"] } } // Response: { "id": "mon_01", "username": "elonmusk", "eventTypes": [...], "createdAt": "..." } // ── List monitors ───────────────────────────────────────────────────────────── { "path": "/api/v1/monitors", "method": "GET" } // ── Pause a monitor ─────────────────────────────────────────────────────────── { "path": "/api/v1/monitors/mon_01", "method": "PATCH", "body": { "isActive": false } } // ── Delete a monitor ────────────────────────────────────────────────────────── { "path": "/api/v1/monitors/mon_01", "method": "DELETE" } // ── Create a keyword monitor ────────────────────────────────────────────────── { "path": "/api/v1/monitors/keywords", "method": "POST", "body": { "query": "TweetClaw OR xquik", "eventTypes": ["tweet.new"] } } // ── List events (with pagination) ───────────────────────────────────────────── { "path": "/api/v1/events", "method": "GET", "query": { "monitorId": "mon_01", "eventType": "tweet.new", "limit": 20 } } // Response: { "events": [{ "id": "evt_01", "eventType": "tweet.new", // "xUsername": "elonmusk", "payload": {...}, "createdAt": "..." }], "hasMore": false } // ── Create a webhook ───────────────────────────────────────────────────────── { "path": "/api/v1/webhooks", "method": "POST", "body": { "url": "https://myapp.com/hooks/xquik", "eventTypes": ["tweet.new", "tweet.reply"] } } // Response: { "id": "wh_01", "url": "...", "secret": "whsec_...", "createdAt": "..." } // ── Test a webhook ──────────────────────────────────────────────────────────── { "path": "/api/v1/webhooks/wh_01/test", "method": "POST" } // Response: { "success": true, "statusCode": 200 } ``` --- ## API: Bulk Extraction Start asynchronous extraction jobs for followers, replies, search results, community members, giveaway entries, and more. Cost: 1 credit per result ($0.00015), 5 credits per article result. ```typescript // ── Estimate extraction cost before running ─────────────────────────────────── { "path": "/api/v1/extractions/estimate", "method": "POST", "body": { "toolType": "follower_extractor", "targetUsername": "elonmusk", "resultsLimit": 1000 } } // Response: { "estimatedResults": 1000, "usagePercent": 5, "allowed": true } // ── Start a follower extraction ─────────────────────────────────────────────── { "path": "/api/v1/extractions", "method": "POST", "body": { "toolType": "follower_extractor", "targetUsername": "elonmusk", "resultsLimit": 500 } } // Response: { "id": "ext_01", "toolType": "follower_extractor", "status": "running" } // ── Start a tweet search extraction ────────────────────────────────────────── { "path": "/api/v1/extractions", "method": "POST", "body": { "toolType": "tweet_search_extractor", "searchQuery": "AI agents", "resultsLimit": 200, "sinceDate": "2024-01-01", "language": "en", "minFaves": 10, "verifiedOnly": false } } // ── Poll extraction results ─────────────────────────────────────────────────── { "path": "/api/v1/extractions/ext_01", "method": "GET", "query": { "limit": 50, "after": "cursor_abc" } } // Response: { "job": { "id": "ext_01", "status": "completed", "totalResults": 500 }, // "results": [...], "hasMore": true, "nextCursor": "cursor_def" } // ── Export extraction results as CSV ────────────────────────────────────────── { "path": "/api/v1/extractions/ext_01/export", "method": "GET", "query": { "format": "csv" } } // Response: CSV file download // ── Run a giveaway draw ─────────────────────────────────────────────────────── { "path": "/api/v1/draws", "method": "POST", "body": { "tweetUrl": "https://x.com/user/status/1234567890", "winnerCount": 3, "filters": { "mustFollow": true, "mustLike": true, "mustRetweet": false } } } // Response: { "id": "drw_01", "tweetId": "1234567890", "totalEntries": 842, // "validEntries": 631, // "winners": [{ "position": 1, "authorUsername": "winner1", "isBackup": false }] } // ── Export draw results ─────────────────────────────────────────────────────── { "path": "/api/v1/draws/drw_01/export", "method": "GET", "query": { "format": "xlsx" } } ``` --- ## API: Media Upload media from URL and download tweet media. Upload costs 10 credits (write action); media download costs 1 credit per file. ```typescript // ── Download media from a tweet ─────────────────────────────────────────────── { "path": "/api/v1/x/media/download", "method": "POST", "body": { "tweetInput": "https://x.com/user/status/1234567890" } } // Response: { "tweetId": "1234567890", "galleryUrl": "https://xquik.com/gallery/abc", "cacheHit": false } // ── Bulk download media from multiple tweets ────────────────────────────────── { "path": "/api/v1/x/media/download", "method": "POST", "body": { "tweetIds": ["111", "222", "333", "444"] } } // Response: { "galleryUrl": "https://xquik.com/gallery/xyz", "totalTweets": 4, "totalMedia": 12 } ``` --- ## Slash Commands Instant responses without LLM involvement; resolved directly by the plugin. ```bash # Show Xquik account status, subscription, usage, and credit balance (API-key mode only) /xstatus # Output: # --- Xquik Account Status --- # X Account: @myaccount # Email: user@example.com # Locale: en # Subscription: Active (pro) # Usage: 42% # Remaining: 5800 # Show trending topics from curated sources (radar – free, works in all modes) /xtrends # Show trending topics filtered by category /xtrends tech # Output: # --- Trending Topics (15 items) --- # 1. OpenAI releases GPT-5 [hacker_news] (score: 98) # https://news.ycombinator.com/item?id=... # 2. Rust 2.0 announced [github] (score: 87) # ... ``` --- ## Event Poller – `createEventPoller` The event poller runs as a registered OpenClaw service, calling `GET /api/v1/events` on a configurable interval and forwarding new events to the agent logger. It uses exponential backoff (capped at 300 s) on consecutive errors. ```typescript import { createEventPoller } from '@xquik/tweetclaw/services/event-poller'; const poller = createEventPoller({ intervalSeconds: 60, request: myRequestFunction, // RequestFunction pointing at https://xquik.com onEvents: (events) => { for (const event of events) { // event shape: { id, eventType, xUsername, payload, createdAt } console.info(`[TweetClaw] ${event['eventType']} from @${event['xUsername']}`); } }, }); // Start polling (first poll fires after intervalSeconds) poller.start(); // Stop polling (e.g. on plugin unload) poller.stop(); // Backoff behavior: // - 0 consecutive errors → intervalSeconds delay // - 1 error → 2× interval (capped at 300 s) // - 2 errors → 4× interval // - N errors → min(2^N × interval, 300) s ``` --- ## MPP Mode – `initMpp` MPP (Machine Payments Protocol) enables anonymous, pay-per-use access to 32 read-only Xquik endpoints without an Xquik account. The `tempoSigningKey` is a 66-character hex private key used to sign on-chain micropayment proofs via the `mppx` SDK. ```typescript import { initMpp } from '@xquik/tweetclaw/mpp'; // Prerequisites: npm i mppx viem // tempoSigningKey: 66-char hex key from `mppx account create` await initMpp('0xabc...def'); // Internally: // 1. Loads 'mppx/client' and 'viem/accounts' dynamically // 2. Calls privateKeyToAccount(tempoSigningKey) to create a viem Account // 3. Wraps it with mppx's tempo({ account }) payment method // 4. Registers the method via Mppx.create({ methods: [method] }) // After init, any HTTP 402 response from xquik.com is automatically // answered with a signed micropayment proof. // In plugin config (stored in OpenClaw, never passed to agent): // { "tempoSigningKey": "0x..." } // MPP mode is read-only – write/monitor/webhook endpoints are blocked. // Eligible endpoints include: tweet lookup, search, user lookup, trends, // followers, following, mentions, communities, lists, media download, etc. ``` --- ## Catalog Internals – `exploreCatalog` / `resolveCatalogRequest` The catalog module filters the static API spec and resolves incoming tool params to validated, safe request objects. All paths must start with `/api/v1/`; query parameters must not be embedded in the path string. ```typescript import { exploreCatalog, resolveCatalogRequest } from '@xquik/tweetclaw/tools/catalog'; // Programmatic catalog search (same as the explore tool): const twitterGetEndpoints = exploreCatalog({ category: 'twitter', method: 'GET', free: false, mpp: true, limit: 10, }); // Returns up to 10 MPP-eligible paid twitter GET endpoints // Resolve a tool call to a safe request object: const resolved = resolveCatalogRequest( { path: '/api/v1/x/tweets/search', method: 'GET', query: { q: 'agents', limit: 20 } }, { mppMode: false }, ); // resolved: { path: '/api/v1/x/tweets/search', method: 'GET', // query: { q: 'agents', limit: '20' }, endpoint: EndpointInfo } // Throws if: // - path doesn't start with /api/v1/ // - path includes ? or # (must use query object) // - method+path combo not found in catalog // - mppMode: true and endpoint has no mpp field // Approval check – returns true for non-GET and sensitive GET paths: import { requestNeedsApproval } from '@xquik/tweetclaw/tools/catalog'; requestNeedsApproval('POST', '/api/v1/x/tweets'); // true – write action requestNeedsApproval('GET', '/api/v1/x/bookmarks'); // true – private data requestNeedsApproval('GET', '/api/v1/x/timeline'); // true – private data requestNeedsApproval('GET', '/api/v1/x/tweets/search'); // false – public read ``` --- ## Summary TweetClaw's primary use cases are AI agent workflows that need to interact with X/Twitter: automating content publishing (tweet, reply, like, retweet, follow, DM) with per-action user approval; researching X data (search, user timelines, thread context, community feeds, trending topics, articles) at a fraction of the official API cost; running giveaway draws from tweet replies with eligibility filters; bulk-extracting followers, mentions, or search results for analysis; and monitoring accounts or keywords for new activity with event delivery into the agent session. The compose/refine/score pipeline and curated radar endpoint are free and work even without a subscription, making TweetClaw useful for content planning workflows that never make a live API call. For integration, TweetClaw is designed to work within the OpenClaw plugin ecosystem: install via `openclaw plugins install @xquik/tweetclaw`, configure credentials with `openclaw config set`, and use the `explore` tool to discover endpoints before invoking them with `tweetclaw`. The two-tool pattern (discover then invoke) minimizes token usage and keeps the agent from guessing paths. For non-OpenClaw environments or framework integrations (Mastra, CrewAI, LangChain, LangGraph, Pydantic AI, Google ADK, n8n, Zapier, Make, Pipedream), the same Xquik REST API (`https://xquik.com/api/v1/`) is accessible directly with an API key in the `Authorization: Bearer` header, with identical endpoint paths and response shapes documented at [docs.xquik.com](https://docs.xquik.com).