Claude MCP Recommended for agents

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.

Install

$ npx @falconai/mcp-server

Published on npm: @falconai/mcp-server ↗ · Local dev: cd packages/falcon-mcp-server && npm install

Claude Desktop config

{
  "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"
      }
    }
  }
}

Tools exposed to Claude

ToolDescription
search_marketsList/filter markets
get_marketMarket detail + snapshot
get_leaderboardTrader rankings (PnL, win rate, risk score)
get_trader_statsFull wallet profile
get_recent_tradesTrade feed
get_copy_picksTopic copy-trade picks
get_orderbookLive L2 book
get_api_usageQuota / usage

OpenClaw skill Agents

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.

Installation

Use the Python SDK or any HTTP client with your API key.

Python SDK v0.1

$ pip install falcon-polymarket

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()

Node.js / cURL (raw HTTP)

$ npm install node-fetch
or Node 18+ built-in fetch

Authentication

Every 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"

Markets

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"

Trade Feed & Trader Analytics Tier 2

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"

Webhooks — Receiving Trade Signals

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.

Create via API

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"]}'

Webhook headers every request

HeaderDescription
X-Falcon-EventEvent type, e.g. trade.executed
X-Falcon-DeliveryUnique delivery ID
X-Falcon-TimestampUnix seconds (use for replay-attack protection)
X-Falcon-Signaturesha256=<hmac> — verify this before processing

Signature verification

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..."

Webhook payload examples

// 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"
}

Error Handling

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
Open Full API Reference Download OpenAPI YAML Get API Key ↗ Manage Webhooks ↗