Official Python SDK, MCP server for Claude Desktop, plus copy-paste Node.js and cURL examples.
Give Claude direct access to markets, leaderboard, trader stats, trades, copy picks, and live order books. The MCP server calls the same REST API your apps use.
Published on npm: @falconai/mcp-server ↗ · Local dev: cd packages/falcon-mcp-server && npm install
{
"mcpServers": {
"falcon-polymarket": {
"command": "npx",
"args": ["-y", "@falconai/mcp-server"],
"env": {
"FALCON_API_KEY": "aif_your_key",
"FALCON_API_BASE": "https://api.falconai.pro/api/v1/external/polymarket"
}
}
}
}
| Tool | Description |
|---|---|
search_markets | List/filter markets |
get_market | Market detail + snapshot |
get_leaderboard | Trader rankings (PnL, win rate, risk score) |
get_trader_stats | Full wallet profile |
get_recent_trades | Trade feed |
get_copy_picks | Topic copy-trade picks |
get_orderbook | Live L2 book |
get_api_usage | Quota / usage |
Use Falcon for Polymarket research inside OpenClaw. Install the skill from ClawHub when available, or download falcon-openclaw-skill.zip from the Falcon agent client page.
openclaw skills install falcon-polymarket
# or copy SKILL.md to ~/.openclaw/skills/falcon-polymarket/
export FALCON_API_KEY=aif_your_key
For live signal execution, run the Falcon AI client on the same machine (Windows .exe or Python zip). Wallet keys stay local.
MCP package for OpenClaw/Cursor: @falconai/polymarket-mcp (see MCP section above) or npx @falconai/mcp-server.
Use the Python SDK or any HTTP client with your API key.
Published on PyPI: falcon-polymarket ↗ · Local dev: pip install -e packages/falcon-polymarket-python
from falcon_polymarket import FalconPolymarketClient with FalconPolymarketClient(api_key="aif_your_key") as client: board = client.get_leaderboard(limit=5, sort_by="total_realized_pnl") stats = client.get_trader_stats("0x...") book = client.get_orderbook("0x...") usage = client.usage()
fetchEvery request must include your API key in the Authorization header. Generate keys at Developer Keys ↗.
// Node.js 18+ — built-in fetch const API_BASE = 'https://api.falconai.pro/api/v1/external/polymarket'; const API_KEY = 'aif_your_key_here'; // from /app/developer/keys const apiFetch = (path, params = {}) => { const url = new URL(API_BASE + path); Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v)); return fetch(url, { headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(r => r.json()); }; // Health check const health = await apiFetch('/health'); console.log(health); // { success: true, data: { status: 'ok' } }
# Python — pip install requests import requests API_BASE = 'https://api.falconai.pro/api/v1/external/polymarket' API_KEY = 'aif_your_key_here' session = requests.Session() session.headers['Authorization'] = f'Bearer {API_KEY}' # Health check resp = session.get(f'{API_BASE}/health') resp.raise_for_status() print(resp.json()) # {'success': True, 'data': {'status': 'ok'}}
# Health check curl https://api.falconai.pro/api/v1/external/polymarket/health \ -H "Authorization: Bearer aif_your_key_here"
List active markets, fetch a single market, or paginate through all 35,000+ markets using cursor-based pagination.
// List top 10 active markets by volume const { data: markets } = await apiFetch('/markets', { status: 'active', sort: 'volume', limit: 10 }); // Single market detail const { data: market } = await apiFetch(`/markets/${marketId}`); // ── Cursor pagination ──────────────────────────────────────── async function getAllMarkets() { let cursor = null; const all = []; do { const resp = await apiFetch('/markets', { status: 'active', limit: 50, ...(cursor && { cursor }) }); all.push(...resp.data); cursor = resp.pagination?.has_more ? resp.pagination.next_cursor : null; } while (cursor); return all; }
# List top 10 active markets by volume markets = session.get( f'{API_BASE}/markets', params={'status': 'active', 'sort': 'volume', 'limit': 10} ).json()['data'] # Single market market = session.get(f'{API_BASE}/markets/{market_id}').json()['data'] # ── Cursor pagination ───────────────────────────────────────── def get_all_markets(): all_markets, cursor = [], None while True: params = {'status': 'active', 'limit': 50} if cursor: params['cursor'] = cursor resp = session.get(f'{API_BASE}/markets', params=params).json() all_markets.extend(resp['data']) if not resp['pagination']['has_more']: break cursor = resp['pagination']['next_cursor'] return all_markets
# List top 10 active markets sorted by volume curl "https://api.falconai.pro/api/v1/external/polymarket/markets?status=active&sort=volume&limit=10" \ -H "Authorization: Bearer aif_your_key" # Single market detail curl "https://api.falconai.pro/api/v1/external/polymarket/markets/0xabc123..." \ -H "Authorization: Bearer aif_your_key" # Next page using cursor curl "https://api.falconai.pro/api/v1/external/polymarket/markets?status=active&limit=50&cursor=eyJ0cyI6..." \ -H "Authorization: Bearer aif_your_key"
Stream recent trades, filter by wallet or market, and fetch per-wallet PnL stats.
// Recent trades (global) const { data: trades } = await apiFetch('/trades', { limit: 50 }); // Trades for a specific wallet const { data: walletTrades } = await apiFetch('/trades', { wallet: '0xba4ac793e68eacb93b41566137f25757656a9fa6', limit: 100 }); // Trader profile (30-day stats + realized PnL) const { data: trader } = await apiFetch( '/traders/0xba4ac793e68eacb93b41566137f25757656a9fa6' ); console.log(trader.total_realized_pnl, trader.win_rate_pct);
# Recent trades (global) trades = session.get(f'{API_BASE}/trades', params={'limit': 50}).json()['data'] # Trades for a specific wallet wallet_trades = session.get(f'{API_BASE}/trades', params={ 'wallet': '0xba4ac793e68eacb93b41566137f25757656a9fa6', 'limit': 100 }).json()['data'] # Trader profile (30-day stats + realized PnL) trader = session.get( f"{API_BASE}/traders/0xba4ac793e68eacb93b41566137f25757656a9fa6" ).json()['data'] print(trader['total_realized_pnl'], trader['win_rate_pct'])
# Recent trades curl "https://api.falconai.pro/api/v1/external/polymarket/trades?limit=50" \ -H "Authorization: Bearer aif_your_key" # Trades for a wallet curl "https://api.falconai.pro/api/v1/external/polymarket/trades?wallet=0xba4ac...&limit=100" \ -H "Authorization: Bearer aif_your_key" # Trader stats curl "https://api.falconai.pro/api/v1/external/polymarket/traders/0xba4ac..." \ -H "Authorization: Bearer aif_your_key"
Subscribe via REST with your API key at POST /api/v1/external/polymarket/webhooks, or use the Developer Webhooks UI. Events are verified with HMAC-SHA256.
curl -X POST https://api.falconai.pro/api/v1/external/polymarket/webhooks \ -H "Authorization: Bearer aif_your_key" \ -H "Content-Type: application/json" \ -d '{"url":"https://your-server.com/hook","events":["trade.executed","trader.large_trade"]}'
| Header | Description |
|---|---|
X-Falcon-Event | Event type, e.g. trade.executed |
X-Falcon-Delivery | Unique delivery ID |
X-Falcon-Timestamp | Unix seconds (use for replay-attack protection) |
X-Falcon-Signature | sha256=<hmac> — verify this before processing |
const crypto = require('crypto'); const express = require('express'); const app = express(); // Use raw body parser so we can compute the exact HMAC app.use(express.json({ verify: (req, _res, buf) => { req.rawBody = buf; } })); const WEBHOOK_SECRET = process.env.FALCON_WEBHOOK_SECRET; // whsec_... app.post('/webhook', (req, res) => { const sig = req.headers['x-falcon-signature']; const ts = req.headers['x-falcon-timestamp']; // Reject events older than 5 minutes (replay-attack guard) if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) { return res.status(400).send('Timestamp too old'); } const msg = `${ts}.${req.rawBody}`; const expected = 'sha256=' + crypto .createHmac('sha256', WEBHOOK_SECRET) .update(msg).digest('hex'); if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) { return res.status(401).send('Bad signature'); } // Signature is valid — handle the event const event = req.body; console.log(`Received ${event.event} for market ${event.market_id}`); // Always respond 2xx quickly — retry logic depends on it res.status(200).send('OK'); });
# Flask webhook receiver — pip install flask import hmac, hashlib, time from flask import Flask, request, abort app = Flask(__name__) SECRET = 'whsec_your_secret' # set from env @app.post('/webhook') def receive_webhook(): sig = request.headers.get('X-Falcon-Signature', '') ts = request.headers.get('X-Falcon-Timestamp', '0') # Replay-attack guard — reject events older than 5 minutes if abs(time.time() - int(ts)) > 300: abort(400, 'Timestamp too old') raw_body = request.get_data() msg = ts.encode() + b'.' + raw_body expected = 'sha256=' + hmac.new( SECRET.encode(), msg, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(sig, expected): abort(401, 'Bad signature') event = request.get_json() print(f"Received {event['event']} for {event.get('market_id','?')}") return 'OK', 200
# HMAC-SHA256 algorithm (language-agnostic) # # 1. Concatenate: message = timestamp + "." + raw_body_string # 2. Compute HMAC: digest = HMAC-SHA256(key=webhook_secret, data=message) # 3. Format: expected = "sha256=" + hex(digest) # 4. Compare: use constant-time comparison to avoid timing attacks # # Reject if: sig != expected OR abs(now - timestamp) > 300 seconds # # Example values: timestamp = "1743600000" raw_body = '{"event":"trade.executed","market_id":"0xabc..."}' secret = "whsec_8c027e334813cbafe38895ca0281f992..." message = timestamp + "." + raw_body # → "1743600000.{"event":"trade.executed",...}" signature = "sha256=" + HMAC_SHA256_HEX(key=secret, data=message) # → "sha256=a3f7e2c8d1..."
// trade.executed { "event": "trade.executed", "trade_id": "0x1a2b3c...", "market_id": "0xabc123...", "market_title": "Will BTC exceed $100k by Dec 2025?", "wallet": "0xba4ac793...", "side": "buy", "outcome": "YES", "price": 0.72, "size_usdc": 250.0, "timestamp": "2026-04-03T15:00:00.000Z" } // market.price_signal { "event": "market.price_signal", "market_id": "0xabc123...", "market_title": "Will XRP dip to $0.60 by December 31, 2026?", "yes_price": 0.44, "prev_price": 0.28, "change_pct": 57.1, "direction": "up", "timestamp": "2026-04-03T15:05:00.000Z" } // market.resolved { "event": "market.resolved", "market_id": "0xdef456...", "market_title": "Will the Fed cut rates in March 2026?", "resolved_outcome": "YES", "final_yes_price": 1.0, "final_no_price": 0.0, "timestamp": "2026-04-03T16:00:00.000Z" } // copy.executed (account-scoped — autonomous copy) { "event": "copy.executed", "user_id": 42, "copy_subscription_id": 7, "leader_wallet": "0xba4ac793...", "leader_trade_id": "0x1a2b3c...", "market_id": "0xabc123...", "side": "buy", "outcome": "YES", "child_size_usdc": 25.0, "leader_size_usdc": 250.0, "clob_order_id": "0xorder...", "trade_intent_id": 901, "status": "submitted", "dry_run": false, "timestamp": "2026-04-03T15:01:00.000Z" } // risk.blocked (account-scoped) { "event": "risk.blocked", "user_id": 42, "copy_subscription_id": 7, "leader_wallet": "0xba4ac793...", "market_id": "0xabc123...", "reason": "max_daily_notional", "leader_size_usdc": 250.0, "trade_intent_id": 902, "timestamp": "2026-04-03T15:01:00.000Z" }
All errors share the same envelope. Check success === false and the code field.
async function safeApiFetch(path, params = {}) { const resp = await apiFetch(path, params); if (!resp.success) { const { code, error } = resp; if (code === 'UNAUTHORIZED') throw new Error('Invalid API key'); if (code === 'FORBIDDEN') throw new Error('Tier too low for this endpoint'); if (code === 'NOT_FOUND') throw new Error(`Not found: ${path}`); if (code === 'PAYMENT_REQUIRED') throw new Error('Insufficient credits'); throw new Error(`API error [${code}]: ${error}`); } return resp; }
def safe_get(path, **params): resp = session.get(f'{API_BASE}{path}', params=params).json() if not resp.get('success'): code = resp.get('code', 'UNKNOWN') msg = resp.get('error', 'Unknown error') error_map = { 'UNAUTHORIZED': 'Invalid API key', 'FORBIDDEN': 'Tier too low for this endpoint', 'NOT_FOUND': f'Not found: {path}', 'PAYMENT_REQUIRED': 'Insufficient credits', } raise Exception(error_map.get(code, f'API error [{code}]: {msg}')) return resp