Claude MCP Recommended for agents

Give Claude direct access to markets, OHLCV, leaderboard, trader browse/PnL, holders, 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_market_ohlcvOHLCV candles (5m / 1h / 1d)
get_leaderboardTrader rankings (PnL, win rate, risk score)
browse_tradersRanked trader directory
get_trader_statsFull wallet profile
get_trader_pnlDaily PnL curve
get_recent_tradesTrade feed (optional min_size)
get_market_holdersTop holders per outcome
get_market_oiOpen interest
get_copy_picksTopic copy-trade picks
get_orderbookLive L2 book
get_api_usageQuota / usage
get_briefingAgent heartbeat (copy picks, signals, paper state)

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 agent hub.

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 falcon-polymarket-agent on the same machine (PyPI, zip, or Windows .exe). Wallet keys stay local. Install guide ↗ · Download page ↗

MCP package for OpenClaw/Cursor: @falconai/polymarket-mcp (see MCP section above) or npx @falconai/mcp-server.

Polymarket agent client Local execution

Autonomous trading runtime that runs on your PC or VPS. Falcon sends signals; your machine applies risk rules and signs Polymarket CLOB orders. Private keys never leave your device.

Install (PyPI)

$ pip install falcon-polymarket-agent

Published on PyPI: falcon-polymarket-agent ↗ · npm bootstrap: npx @falconai/agent-client

# Preflight (API key + WebSocket + platform tether)
falcon-polymarket-agent-check

# Run client + dashboard at http://localhost:8080
falcon-polymarket-agent

Other install paths

Zip + Python, Windows .exe (no Python), and Docker are on the agent client download page ↗. Configuration reference: .env guide ↗

Requirements

Installation

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

Python SDK v0.1.2

$ 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")
    candles = client.get_ohlcv("0x...", interval="1h")
    holders = client.get_market_holders("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 (id or slug), OHLCV candles, 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 (conditionId or slug)
const { data: market } = await apiFetch(`/markets/${marketId}`);

// OHLCV candles
const { data: candles } = await apiFetch(`/markets/${marketId}/ohlcv`, {
  interval: '1h', limit: 168
});

// ── 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']

# Hourly OHLCV
candles = session.get(
  f'{API_BASE}/markets/{market_id}/ohlcv',
  params={'interval': '1h', 'limit': 168}
).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"

# Hourly OHLCV
curl "https://api.falconai.pro/api/v1/external/polymarket/markets/0xabc123.../ohlcv?interval=1h&limit=168" \
  -H "Authorization: Bearer aif_your_key"

# Categories + platform volume
curl "https://api.falconai.pro/api/v1/external/polymarket/markets/categories" \
  -H "Authorization: Bearer aif_your_key"
curl "https://api.falconai.pro/api/v1/external/polymarket/volume/timeseries?range_days=30" \
  -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, browse ranked traders, and fetch per-wallet PnL, holders, and open interest.

// 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 (lifetime + 30-day stats)
const { data: trader } = await apiFetch(
  '/traders/0xba4ac793e68eacb93b41566137f25757656a9fa6'
);
console.log(trader.total_realized_pnl, trader.win_rate_pct);

// Daily PnL curve + top holders (Tier 2)
const { data: pnl } = await apiFetch('/traders/0xba4ac.../pnl', { days: 90 });
const { data: holders } = await apiFetch(`/markets/${marketId}/holders`);
# 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'])

# Daily PnL + holders (Tier 2)
pnl = session.get(f'{API_BASE}/traders/{wallet}/pnl', params={'days': 90}).json()['data']
holders = session.get(f'{API_BASE}/markets/{market_id}/holders').json()['data']
# 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 profile + daily PnL + holders
curl "https://api.falconai.pro/api/v1/external/polymarket/traders/0xba4ac..." \
  -H "Authorization: Bearer aif_your_key"
curl "https://api.falconai.pro/api/v1/external/polymarket/traders/browse?sort_by=total_realized_pnl&limit=25" \
  -H "Authorization: Bearer aif_your_key"
curl "https://api.falconai.pro/api/v1/external/polymarket/markets/0xabc.../holders" \
  -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"
}

// strategy.signal (account-scoped — Strategy Studio)
{
  "event": "strategy.signal",
  "signal_id": "strat_1a2b3c4d",
  "signal_type": "strategy_lab",
  "strategy_id": 12,
  "strategy_name": "YES dip buyer",
  "market_id": "0xabc123...",
  "market_title": "Will BTC exceed $100k by Dec 2026?",
  "side": "buy",
  "entry_price": 0.42,
  "confidence": 0.75,
  "edge": 0.08,
  "emitted_at": "2026-04-03T15:02: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 ↗