From xbird
Accesses Twitter/X search and mentions data via Virtuals Protocol's Agent Commerce Protocol (ACP) with E2E ECDH-encrypted credentials for secure agent-to-agent commerce.
npx claudepluginhub checkra1neth/xbird-skillThis skill uses the workspace's default tool permissions.
Access Twitter/X data through Virtuals Protocol agent-to-agent commerce. Credentials are ECDH-encrypted client-side — even the protocol relay cannot read them.
Accesses Twitter/X data via stateless pay-per-request REST API using x402 USDC micropayments on Base mainnet. For backend services, autonomous agents, and programmatic integrations via HTTP.
Provides 68+ MCP tools for AI agents to automate X/Twitter: scrape profiles/followers/tweets, post/like/retweet/reply, analyze sentiment/reputation, manage DMs/workflows. Uses Puppeteer; no API keys needed.
Interacts with X (Twitter) via Xquik API: search tweets/users/followers, post replies/likes/retweets, send DMs, download media, real-time account monitoring, bulk data extraction using 113 REST endpoints.
Share bugs, ideas, or general feedback.
Access Twitter/X data through Virtuals Protocol agent-to-agent commerce. Credentials are ECDH-encrypted client-side — even the protocol relay cannot read them.
Don't use when: Running inside Claude Code / Cursor (use MCP instead), or making direct HTTP calls (use REST x402 instead).
acp setup or from config.json LITE_AGENT_API_KEYauth_token and ct0 cookies from an authenticated Twitter session| Endpoint | URL |
|---|---|
| Virtuals REST API | https://claw-api.virtuals.io |
| Virtuals Socket.io | https://acpx.virtuals.io |
| xbird TEE attestation | https://xbirdapi.up.railway.app/tee/attestation |
encryption-flow.md)encryptedCredentialspolling.md)Offering name: twitter_search
| Method | Params | Description |
|---|---|---|
search | { query: string, count?: number, cursor?: string } | Search tweets. Default count: 20. |
getMentions | { handle: string, count?: number } | Get mentions for a handle. |
import {
generateKeyPair, exportPublicKey, importPublicKey, deriveSharedKey, encrypt,
} from "./acp/tee/crypto.ts";
const SERVER = "https://xbirdapi.up.railway.app";
const ACP_API = "https://claw-api.virtuals.io";
// 1. Attestation + ECDH
const att = await fetch(`${SERVER}/tee/attestation`).then(r => r.json());
const clientKP = await generateKeyPair();
const clientPub = await exportPublicKey(clientKP.publicKey);
const sharedKey = await deriveSharedKey(clientKP.privateKey, await importPublicKey(att.publicKey));
const { iv, ciphertext } = await encrypt(sharedKey, JSON.stringify({ authToken, ct0 }));
// 2. Create job — serviceRequirements MUST be a plain object
const res = await fetch(`${ACP_API}/acp/jobs`, {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": apiKey },
body: JSON.stringify({
providerWalletAddress: providerWallet,
jobOfferingName: "twitter_search",
serviceRequirements: {
method: "search",
params: { query: "AI agents", count: 20 },
encryptedCredentials: { ephemeralPublicKey: clientPub, iv, ciphertext },
},
}),
});
const jobId = (await res.json())?.data?.jobId;
// 3. Poll (see polling.md for full implementation)
Encryption details: see encryption-flow.md. Polling + socket.io optimization: see polling.md.
| Mistake | Fix |
|---|---|
Double-stringified serviceRequirements | Must be a plain object inside JSON.stringify(), NOT JSON.stringify(JSON.stringify(...)). |
| Wrong API key (401) | Use buyer key (LITE_AGENT_API_KEY), not seller key. |
| Job REJECTED: "No offering name" | Use jobOfferingName: "twitter_search" exactly. |
| Missing encryptedCredentials | Verify ECDH step: ephemeralPublicKey, iv, ciphertext all must be present. |
| Stuck in REQUEST | Provider may be offline. Verify wallet address and ACP runtime status. |
| Response shape varies | Always try data?.data?.data ?? data?.data ?? data to extract job. |
| Phase is numeric via socket.io | Normalize: PHASE_MAP[phase] where {0:"REQUEST",...,6:"EXPIRED"}. |