diff --git a/skills/onchainexpat/x402/SKILL.md b/skills/onchainexpat/x402/SKILL.md new file mode 100755 index 000000000..2aee3e316 --- /dev/null +++ b/skills/onchainexpat/x402/SKILL.md @@ -0,0 +1,169 @@ +--- +name: x402 +description: Pay for x402 APIs autonomously with USDC. Discover endpoints via Bazaar, execute payments, access paid services. +metadata: {"clawdbot":{"emoji":"šŸ’ø","homepage":"https://x402.org","requires":{"env":["X402_PRIVATE_KEY"]},"primaryEnv":"X402_PRIVATE_KEY","install":[{"id":"npm","kind":"node","package":"@civic/x402-mcp","bins":["npx"],"label":"Install x402-mcp (npm)"}]}} +--- + +# x402 - Autonomous Agent Payments + +Pay for x402-enabled APIs with USDC on Base. Discover paid endpoints via the Bazaar, execute micropayments, and access services without accounts or API keys. + +## What is x402? + +x402 is an open payment protocol that enables AI agents to pay for API access autonomously using stablecoins (USDC). When a service returns HTTP 402 "Payment Required", the agent can automatically sign a payment and retry the request. + +## Quick Start + +### 1. Set up your wallet + +Export a private key from a wallet with USDC on Base (mainnet or Sepolia testnet): + +```bash +export X402_PRIVATE_KEY="0x..." +``` + +**āš ļø Security**: Use a dedicated wallet with limited funds for agent payments. Never use your main wallet. + +### 2. Fund your wallet + +- **Testnet (Base Sepolia)**: Get test USDC from [Coinbase Faucet](https://portal.cdp.coinbase.com/products/faucet) +- **Mainnet (Base)**: Bridge USDC to Base via [bridge.base.org](https://bridge.base.org) + +## Discovering x402 Endpoints + +### Query the Bazaar + +The x402 Bazaar is the discovery layer for paid APIs. Query it to find available services: + +```bash +# List all available x402 services +curl -s "https://x402.org/facilitator/discovery/resources?limit=20" | jq '.resources[] | {url: .resource, price: .accepts[0].price, network: .accepts[0].network}' + +# Search by category (if supported) +curl -s "https://x402.org/facilitator/discovery/resources?type=http&limit=50" | jq '.' +``` + +### Alternative Directories + +- **x402.org/ecosystem** - Curated list of x402-enabled services +- **x402index.com** - Community directory of x402 endpoints +- **x402apis.io** - Decentralized API registry on Solana + +## Making Paid Requests + +### Using @civic/x402-mcp (Recommended for MCP) + +If running as an MCP server (e.g., with Claude Desktop), configure in `~/.config/claude/claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "x402": { + "command": "npx", + "args": ["@civic/x402-mcp"], + "env": { + "PRIVATE_KEY": "${X402_PRIVATE_KEY}", + "TARGET_URL": "https://x402-mcp.fly.dev/mcp" + } + } + } +} +``` + +### Using curl with manual payment flow + +```bash +# Step 1: Make initial request (will get 402) +curl -i https://api.example.com/x402/endpoint + +# Step 2: Parse payment requirements from 402 response +# Look for X-PAYMENT-REQUIRED header with payment details + +# Step 3: Sign payment and retry (requires wallet integration) +``` + +### Using the x402 TypeScript SDK + +```typescript +import { x402Client, wrapAxiosWithPayment } from "@x402/axios"; +import { registerExactEvmScheme } from "@x402/evm/exact/client"; +import { privateKeyToAccount } from "viem/accounts"; +import axios from "axios"; + +// Create x402 client +const client = new x402Client(); +const signer = privateKeyToAccount(process.env.X402_PRIVATE_KEY); +registerExactEvmScheme(client, { signer }); + +// Wrap axios with payment handling +const api = wrapAxiosWithPayment(axios.create(), client); + +// Make paid request - payment handled automatically on 402 +const response = await api.get("https://api.example.com/x402/weather"); +``` + +## Common x402 Endpoints + +### Weather Data +- Price: ~$0.001/request +- Returns real-time weather data + +### AI Inference +- Price: varies by model +- Run inference on hosted models + +### Data APIs +- Price: ~$0.001-0.01/request +- Access premium data feeds + +## Environment Variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `X402_PRIVATE_KEY` | Yes | Hex-encoded private key (with 0x prefix) | +| `X402_NETWORK` | No | `base` (mainnet) or `base-sepolia` (testnet). Default: `base-sepolia` | +| `X402_MAX_PAYMENT` | No | Maximum payment per request in USDC (e.g., `0.10`). Default: unlimited | + +## Checking Wallet Balance + +```bash +# Check USDC balance on Base Sepolia +cast balance --erc20 0x036CbD53842c5426634e7929541eC2318f3dCF7e $WALLET_ADDRESS --rpc-url https://sepolia.base.org + +# Check USDC balance on Base Mainnet +cast balance --erc20 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 $WALLET_ADDRESS --rpc-url https://mainnet.base.org +``` + +## Security Best Practices + +1. **Dedicated wallet**: Create a separate wallet just for agent payments +2. **Limited funding**: Only keep small amounts of USDC in the agent wallet +3. **Max payment limits**: Set `X402_MAX_PAYMENT` to cap per-request spending +4. **Testnet first**: Always test on Base Sepolia before mainnet +5. **Monitor spending**: Track wallet balance and transaction history + +## Troubleshooting + +### "Insufficient funds" +- Check USDC balance on the correct network (Base vs Base Sepolia) +- Ensure you have ETH for gas fees + +### "Payment verification failed" +- Verify the facilitator URL is reachable +- Check that your wallet address matches the signer + +### "Network mismatch" +- Confirm the endpoint's required network matches your wallet's network +- Some endpoints only support mainnet or testnet + +## Resources + +- [x402 Documentation](https://docs.cdp.coinbase.com/x402) +- [x402 Protocol Spec](https://x402.org) +- [Coinbase x402 GitHub](https://github.com/coinbase/x402) +- [Base Network](https://base.org) + +## Related Skills + +- `solana-swaps` - For Solana-based x402 payments +- `crypto-tracker` - Monitor wallet balances diff --git a/skills/onchainexpat/x402/bazaar.js b/skills/onchainexpat/x402/bazaar.js new file mode 100755 index 000000000..615ac4998 --- /dev/null +++ b/skills/onchainexpat/x402/bazaar.js @@ -0,0 +1,150 @@ +#!/usr/bin/env node +/** + * x402 Bazaar Discovery CLI + * + * Query the x402 Bazaar to discover paid API endpoints. + * + * Usage: + * node bazaar.js list [--limit N] + * node bazaar.js search + * node bazaar.js info + */ + +const FACILITATOR_URL = process.env.X402_FACILITATOR_URL || 'https://x402.org/facilitator'; + +async function listResources(limit = 20) { + const url = `${FACILITATOR_URL}/discovery/resources?type=http&limit=${limit}`; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (!data.resources || data.resources.length === 0) { + console.log('No x402 services found in the Bazaar.'); + return; + } + + console.log(`\nšŸ“¦ Found ${data.resources.length} x402 services:\n`); + + for (const resource of data.resources) { + const accepts = resource.accepts?.[0] || {}; + const price = accepts.price || accepts.maxAmountRequired || 'N/A'; + const network = accepts.network || 'unknown'; + + console.log(` šŸ”— ${resource.resource}`); + console.log(` šŸ’° Price: ${price}`); + console.log(` 🌐 Network: ${network}`); + if (resource.description) { + console.log(` šŸ“ ${resource.description}`); + } + console.log(''); + } + + return data.resources; + } catch (error) { + console.error(`Error querying Bazaar: ${error.message}`); + process.exit(1); + } +} + +async function getResourceInfo(resourceUrl) { + const url = `${FACILITATOR_URL}/discovery/resources?resource=${encodeURIComponent(resourceUrl)}`; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + console.log(JSON.stringify(data, null, 2)); + return data; + } catch (error) { + console.error(`Error fetching resource info: ${error.message}`); + process.exit(1); + } +} + +// Alternative: Query CDP facilitator directly +async function listFromCDP(limit = 20) { + const url = `https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?limit=${limit}`; + + try { + const response = await fetch(url); + if (!response.ok) { + // Fall back to x402.org + console.log('CDP facilitator unavailable, trying x402.org...'); + return listResources(limit); + } + + const data = await response.json(); + return data; + } catch (error) { + console.log('CDP facilitator unavailable, trying x402.org...'); + return listResources(limit); + } +} + +// Main CLI +const args = process.argv.slice(2); +const command = args[0]; + +switch (command) { + case 'list': + const limit = args.includes('--limit') + ? parseInt(args[args.indexOf('--limit') + 1]) + : 20; + listResources(limit); + break; + + case 'search': + const query = args[1]; + if (!query) { + console.error('Usage: bazaar.js search '); + process.exit(1); + } + // Search is just filtered list for now + listResources(50).then(resources => { + if (resources) { + const filtered = resources.filter(r => + r.resource.toLowerCase().includes(query.toLowerCase()) || + (r.description && r.description.toLowerCase().includes(query.toLowerCase())) + ); + if (filtered.length === 0) { + console.log(`No services matching "${query}" found.`); + } + } + }); + break; + + case 'info': + const resourceUrl = args[1]; + if (!resourceUrl) { + console.error('Usage: bazaar.js info '); + process.exit(1); + } + getResourceInfo(resourceUrl); + break; + + default: + console.log(` +x402 Bazaar Discovery CLI + +Commands: + list [--limit N] List available x402 services (default: 20) + search Search services by keyword + info Get detailed info about a specific endpoint + +Environment: + X402_FACILITATOR_URL Override facilitator URL (default: https://x402.org/facilitator) + +Examples: + node bazaar.js list --limit 50 + node bazaar.js search weather + node bazaar.js info https://api.example.com/x402/data + `); +}