UNPKG

x-developer

Version:

X (Twitter) data platform skill for AI coding agents. 100+ REST API endpoints, 2 MCP tools, 23 extraction types, HMAC webhooks.

193 lines (156 loc) 6.93 kB
# Xquik Workflow Examples Code examples for common integration patterns. ## Authentication ```javascript const API_KEY = "xq_YOUR_KEY_HERE"; const BASE = "https://xquik.com/api/v1"; const headers = { "x-api-key": API_KEY, "Content-Type": "application/json" }; ``` ## Retry with Exponential Backoff Retry only `429` and `5xx`. Never retry `4xx` (except 429). Max 3 retries: ```javascript async function xquikFetch(path, options = {}) { const baseDelay = 1000; for (let attempt = 0; attempt <= 3; attempt++) { const response = await fetch(`${BASE}${path}`, { ...options, headers: { ...headers, ...options.headers }, }); if (response.ok) return response.json(); const retryable = response.status === 429 || response.status >= 500; if (!retryable || attempt === 3) { const error = await response.json(); throw new Error(`Xquik API ${response.status}: ${error.error}`); } const retryAfter = response.headers.get("Retry-After"); const delay = retryAfter ? parseInt(retryAfter, 10) * 1000 : baseDelay * Math.pow(2, attempt) + Math.random() * 1000; await new Promise((resolve) => setTimeout(resolve, delay)); } } ``` ## Cursor Pagination Events, draws, extractions, and extraction results use cursor-based pagination. When more results exist, the response includes `hasMore: true` and a `nextCursor` string. Pass `nextCursor` as the `after` query parameter. ```javascript async function fetchAllPages(path, dataKey) { const results = []; let cursor; while (true) { const params = new URLSearchParams({ limit: "100" }); if (cursor) params.set("after", cursor); const data = await xquikFetch(`${path}?${params}`); results.push(...data[dataKey]); if (!data.hasMore) break; cursor = data.nextCursor; } return results; } ``` Cursors are opaque strings. Never decode or construct them manually. ## Complete Extraction Workflow ```javascript // Step 1: Estimate cost before running const estimate = await xquikFetch("/extractions/estimate", { method: "POST", body: JSON.stringify({ toolType: "follower_explorer", targetUsername: "elonmusk", resultsLimit: 1000, }), }); if (!estimate.allowed) { console.log(`Need ${estimate.creditsRequired} credits; available ${estimate.creditsAvailable}`); return; } // Step 2: Create extraction job let job = await xquikFetch("/extractions", { method: "POST", body: JSON.stringify({ toolType: "follower_explorer", targetUsername: "elonmusk", resultsLimit: 1000, }), }); // Step 3: Poll until complete while (job.status === "pending" || job.status === "running") { await new Promise((r) => setTimeout(r, 2000)); job = await xquikFetch(`/extractions/${job.id}`); } // Step 4: Retrieve paginated results (up to 1,000 per page) let cursor; const allResults = []; while (true) { const path = `/extractions/${job.id}${cursor ? `?after=${cursor}` : ""}`; const page = await xquikFetch(path); allResults.push(...page.results); if (!page.hasMore) break; cursor = page.nextCursor; } // Step 5: Export as CSV/JSON/MD/MD-document/PDF/TXT/XLSX (100,000 row limit; PDF 10,000) const exportUrl = `${BASE}/extractions/${job.id}/export?format=csv`; const csvResponse = await fetch(exportUrl, { headers }); const csvData = await csvResponse.text(); ``` ## Real-Time Monitoring Setup 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. ```javascript // 1. Create monitor (persistent resource; active monitors are metered hourly) const monitor = await xquikFetch("/monitors", { method: "POST", body: JSON.stringify({ username: "elonmusk", eventTypes: ["tweet.new", "tweet.reply", "tweet.quote", "tweet.retweet"], }), }); // 2. Register webhook (persistent delivery destination) const webhook = await xquikFetch("/webhooks", { method: "POST", body: JSON.stringify({ url: "https://your-server.com/webhook", eventTypes: ["tweet.new", "tweet.reply"], }), }); // IMPORTANT: Save webhook.secret. It is shown only once! // 3. Poll events (alternative to webhooks) const events = await xquikFetch("/events?monitorId=7&limit=50"); ``` Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `webhook.test`. ## Endpoint Guide | Goal | Endpoint | Cost | |------|----------|------| | **Get a single tweet** by ID/URL | `GET /x/tweets/{id}` | 1 credit | | **Get an X Article** by tweet ID | `GET /x/articles/{id}` | 5 credits | | **Search tweets** by keyword/hashtag | `GET /x/tweets/search?q=...` | 1 credit/tweet | | **Get a user profile** | `GET /x/users/{username}` | 1 credit | | **Get user's recent tweets** | `GET /x/users/{id}/tweets` | 1 credit/tweet | | **Get user's liked tweets** | `GET /x/users/{id}/likes` | 1 credit/result | | **Get user's media tweets** | `GET /x/users/{id}/media` | 1 credit/result | | **Get tweet favoriters** | `GET /x/tweets/{id}/favoriters` | 1 credit/result | | **Get mutual followers** | `GET /x/users/{id}/followers-you-know` | 1 credit/result | | **Check follow relationship** | `GET /x/followers/check?source=A&target=B` | 5 credits | | **Get trending topics** | `GET /trends?woeid=1` | 3 credits | | **Get radar (trending news)** | `GET /radar?source=hacker_news` | Free | | **Get bookmarks** | `GET /x/bookmarks` | 1 credit/result | | **Get bookmark folders** | `GET /x/bookmarks/folders` | 1 credit | | **Get notifications** | `GET /x/notifications` | 1 credit/result | | **Get home timeline** | `GET /x/timeline` | 1 credit/result | | **Get DM history** | `GET /x/dm/{userId}/history` | 1 credit/result | | **Monitor an X account** | `POST /monitors` | Active monitors are metered hourly | | **Poll for events** | `GET /events` | Free | | **Receive events via webhook** | `POST /webhooks` | Free; confirmation required for destination URL | | **Run a giveaway draw** | `POST /draws` | 1 credit/entry | | **Download tweet media** | `POST /x/media/download` | 1 credit/item | | **Extract bulk data** | `POST /extractions` | 1-5 credits/result | | **Check credits** | `GET /credits` | Free | | **Top up credits** | `POST /credits/topup` | Exact amount confirmation required | | **Compose a tweet** | `POST /compose` | Free | | **Post a tweet** | `POST /x/tweets` | 10 credits | | **Like / Unlike a tweet** | `POST` / `DELETE /x/tweets/{id}/like` | 10 credits | | **Retweet** | `POST /x/tweets/{id}/retweet` | 10 credits | | **Follow / Unfollow** | `POST` / `DELETE /x/users/{id}/follow` | 10 credits | | **Send a DM** | `POST /x/dm/{userId}` | 10 credits | | **Update profile** | `PATCH /x/profile` | 10 credits | | **Upload media** | `POST /x/media` | 10 credits | | **Community actions** | `POST /x/communities`, join/leave | 10 credits | | **Support tickets** | `POST /support/tickets` | Free |