Skip to main content

API reference

Idmon API — Documentation

Calibrated, real-time prediction-market intelligence — delivered as signed webhooks, a WebSocket stream, and a REST API. Base URL: https://api.idmon.io.

Building an AI agent? The same forensic layer is also available as a hosted MCP server — see the MCP docs & pricing.

Get started

Quickstart

Three steps from zero to live data.

Get your key

Email [email protected] to request access. Tell us your use case and we'll confirm the right tier, provision your API key, and — for Operator — configure your webhook. Usually within one business day.

Request access

Make your first call (Developer)

Once you have a key, fetch recent signal alerts:

shell
curl -s https://api.idmon.io/api/alerts/recent?limit=5 \
  -H "Authorization: Bearer pmp_dev_your_key_here"

Example response:

json
[
  {
    "conditionId": "0xabc123...",
    "alertType": "whale_trade",
    "question": "Will the Fed cut rates in July 2026?",
    "category": "economics",
    "currentPrices": { "Yes": 0.62, "No": 0.38 },
    "priceChangePct": 4.8,
    "volume24h": 1240000,
    "sentAt": "2026-06-19T10:14:22Z",
    "message": "Whale bought $85K YES at 0.62"
  }
]

Receive data

Operator: We configure signed webhooks to push signal embeds directly to your Discord channel or endpoint — within ~1.5 s of an alert. See Webhooks for the payload contract and signature verification.

Developer: Connect the WebSocket stream for a live push of every alert as it fires. See WebSocket for the connect URL, message types, and a Node.js example.

Authentication

All REST endpoints require your API key as a Bearer token in the Authorization header. Do not pass it as a query parameter for REST.

http header
Authorization: Bearer <your-api-key>

WebSocket connections authenticate via a ?key= query parameter on the connect URL (bearer headers are not supported at the WS handshake — see WebSocket).

Key prefixes

Your key prefix tells you which tier you're on:

Prefix Tier
pmp_op_ Operator
pmp_dev_ Developer
pmp_ent_ Enterprise
Invalid or over-limit keys return 401 Unauthorized. If you see a 401 mid-session your daily quota may have reset — check your usage against the rate limits table.

REST API

Base URL: https://api.idmon.io. Every /api/* path requires the Authorization: Bearer <key> header. Responses are JSON. Errors follow standard HTTP status codes.

GET /api/health any tier

Returns service status, uptime, your tier, rate-limit headroom, and server memory. Use this to confirm connectivity and inspect your plan limits.

shell
curl -s https://api.idmon.io/api/health \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
{
  "status": "ok",
  "tier": "developer",
  "uptime": 432800,
  "rateLimit": { "remaining": 9741, "limit": 10000, "resetsAt": "2026-06-20T00:00:00Z" },
  "memoryMb": 182,
  "ts": "2026-06-19T11:04:00Z"
}
GET /api/alerts/recent Developer+

Returns recent signal alerts, newest first. The quickstart example uses this endpoint.

Query param Type Description
limitdefault 50 integer Maximum number of alerts to return.
type string Filter by alert type, e.g. whale_trade, volume_surge.
shell
curl -s "https://api.idmon.io/api/alerts/recent?limit=50&type=whale_trade" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "conditionId": "0xabc123...",
    "alertType": "whale_trade",
    "question": "Will the Fed cut rates in July 2026?",
    "category": "economics",
    "currentPrices": { "Yes": 0.62, "No": 0.38 },
    "priceChangePct": 4.8,
    "volume24h": 1240000,
    "sentAt": "2026-06-19T10:14:22Z",
    "message": "Whale bought $85K YES at 0.62"
  }
]
GET /api/alerts/counts Developer+

Returns a histogram of alert counts by type over the requested window. Useful for building dashboards or spotting unusual activity.

Query param Type Description
hoursdefault 24 integer Window size in hours to aggregate over.
shell
curl -s "https://api.idmon.io/api/alerts/counts?hours=24" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
{
  "hours": 24,
  "counts": {
    "whale_trade": 18,
    "volume_surge": 7,
    "price_spike": 3
  },
  "since": "2026-06-18T11:00:00Z"
}
GET /api/whales/recent Developer+

Recent large-trade events, each with side, size, and whale/mega-whale classification.

Query param Type Description
limitdefault 20 integer Maximum number of events to return.
shell
curl -s "https://api.idmon.io/api/whales/recent?limit=20" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "side": "YES",
    "sizeUsd": 150000,
    "price": 0.71,
    "question": "Will BTC close above $100K in June?",
    "category": "crypto",
    "timestamp": "2026-06-19T09:52:11Z",
    "isMegaWhale": true
  }
]
GET /api/whales/stats Developer+

Aggregate whale statistics — total all-time, mega-whale count, and rolling 24-hour volume.

shell
curl -s https://api.idmon.io/api/whales/stats \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
{
  "totalWhaleAlerts": 4120,
  "megaWhaleAlerts": 312,
  "whaleAlerts24h": 18
}
GET /api/markets/top Developer+

Top markets by 24-hour volume, with current outcome prices and liquidity. Optionally filter by category.

Query param Type Description
limitdefault 20 integer Maximum number of markets to return.
category string Filter by category slug, e.g. politics, crypto, economics.
shell
curl -s "https://api.idmon.io/api/markets/top?limit=20&category=politics" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "conditionId": "0xdef456...",
    "question": "Will Labour win the next UK general election?",
    "category": "politics",
    "endDate": "2029-01-31T00:00:00Z",
    "volume24h": 3100000,
    "liquidity": 820000,
    "outcomePrices": { "Yes": 0.54, "No": 0.46 },
    "url": "https://polymarket.com/event/..."
  }
]
GET /api/wallets/top Developer+

Top-performing wallets ranked by win rate, with trade counts, streaks, and total volume.

Query param Type Description
ndefault 20 integer Number of wallets to return.
shell
curl -s "https://api.idmon.io/api/wallets/top?n=20" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "walletAddress": "0x1a2b3c...",
    "username": "sharpshooter",
    "correctTrades": 84,
    "totalTrades": 102,
    "winRate": 0.824,
    "currentStreak": 7,
    "totalVolumeUsd": 540000,
    "polymarketUrl": "https://polymarket.com/profile/0x1a2b3c..."
  }
]
GET /api/whales/accuracy Developer+

Which whales actually win — not just who's big. Per-wallet win rate, Brier calibration (lower is better), profit factor, average hold time, breadth, and a smart/dumb classification. Sort by win rate, calibration, or profit factor. This is the accuracy layer trackers don't expose.

Query paramTypeDescription
limitdefault 30integerMaximum wallets to return (max 100).
minTradesdefault 20integerMinimum resolved trades for a wallet to qualify.
sortdefault winRatestringOne of winRate, brier (best-calibrated first), profitFactor.
shell
curl -s "https://api.idmon.io/api/whales/accuracy?limit=20&sort=brier" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "walletAddress": "0x1a2b3c...",
    "username": "sharpshooter",
    "classification": "smart",
    "winRate": 0.667,
    "brierScore": 0.18,
    "profitFactor": 2.1,
    "totalTrades": 120,
    "avgHoldHours": 36.5,
    "distinctCategories": 4,
    "currentStreak": 5,
    "bestCategory": "politics",
    "polymarketUrl": "https://polymarket.com/profile/0x1a2b3c..."
  }
]
GET /api/smart-money Developer+

Where the smart money is positioned: net YES flow from historically-accurate wallets (>60% win rate) vs low-accuracy wallets (<45%), per market. Returns the latest snapshot per market ranked by the smart–dumb delta, or pass conditionId for one market's time series.

Query paramTypeDescription
limitdefault 30integerMaximum rows to return (max 100).
conditionIdstringReturn the time series for a single market instead of the latest-per-market ranking.
shell
curl -s "https://api.idmon.io/api/smart-money?limit=20" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "conditionId": "0xabc123...",
    "question": "Will the Fed cut rates in September?",
    "category": "economics",
    "smartMoneyNetYes": 142000,
    "dumbMoneyNetYes": -38000,
    "smartWalletCount": 11,
    "dumbWalletCount": 6,
    "smartDumbDelta": 180000,
    "signal": "smart_bullish",
    "computedAt": 1718900000000
  }
]
GET /api/resolutions Developer+

Recent market resolutions with a calibrated, on-chain-anchored truth label — not just the winning outcome, but a calibrated P(label correct), which sources agreed, the on-chain settlement state, and dispute/review flags. Filter to contested resolutions with reviewOnly=true.

Query paramTypeDescription
limitdefault 50integerMaximum resolutions to return (max 200).
categorystringFilter by category slug.
reviewOnlybooleanOnly return resolutions flagged as disputed or needing review.
shell
curl -s "https://api.idmon.io/api/resolutions?limit=50&reviewOnly=true" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "conditionId": "0xabc123...",
    "question": "Will BTC close above $100k on Dec 31?",
    "category": "crypto",
    "winningOutcome": "YES",
    "labelPosterior": 0.999,
    "winningOutcomeSource": "onchain",
    "settlementState": "finalized",
    "nSourcesAgree": 4,
    "nSourcesTotal": 4,
    "disputeFlag": false,
    "reviewFlag": false,
    "ambiguityFlags": [],
    "resolvedAt": 1735689600000
  }
]
GET /api/resolutions/:conditionId Developer+

Full resolution truth for one market, including the per-source evidence trail — the on-chain payout, Gamma, CLOB and price-implied readings — each joined to that source's measured reliability. Returns 404 if the market hasn't resolved.

shell
curl -s "https://api.idmon.io/api/resolutions/0xabc123..." \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
{
  "conditionId": "0xabc123...",
  "question": "Will BTC close above $100k on Dec 31?",
  "winningOutcome": "YES",
  "labelPosterior": 0.999,
  "winningOutcomeSource": "onchain",
  "settlementState": "finalized",
  "nSourcesAgree": 4,
  "nSourcesTotal": 4,
  "disputeFlag": false,
  "reviewFlag": false,
  "ambiguityFlags": [],
  "resolvedAt": 1735689600000,
  "evidence": [
    { "source": "onchain", "outcomeSide": "YES", "reliability": 0.999 },
    { "source": "gamma", "outcomeSide": "YES", "reliability": 0.95 }
  ]
}
GET /api/cross-market/divergence Developer+

Where a market disagrees with the outside world: the gap between the market price and the poll-implied (politics) or bookmaker-implied (sports) probability. Latest gap per market, signed (consensus − market) in percentage points.

Query paramTypeDescription
sourcedefault allstringall, polls (politics), or odds (sports).
minGapPpdefault 0numberMinimum absolute gap, in percentage points.
categorystringFilter by category slug.
limitdefault 30integerMax rows to return (max 100).
shell
curl -s "https://api.idmon.io/api/cross-market/divergence?source=polls&minGapPp=5" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "conditionId": "0xabc123...",
    "question": "Will candidate X win?",
    "category": "politics_geo",
    "source": "polls",
    "marketProb": 0.40,
    "consensusProb": 0.50,
    "gapPp": 10.0,
    "direction": "consensus_higher",
    "sampleSize": 12,
    "emittedAt": 1718900000000,
    "signalOutcome": null
  }
]
GET /api/cross-market/venue-divergence Developer+

Where Polymarket and Kalshi price the same market apart. Matched cross-venue pairs (passed a hardened 4-gate matcher) where the two venues disagree, ranked by spread — the cross-platform divergence signal.

Query paramTypeDescription
limitdefault 30integerMax rows (max 100).
minSpreadPctdefault 0numberMinimum cross-venue spread, in percentage points.
platformstringkalshi or manifold (the counter-venue).
verifiedOnlybooleanOnly human-confirmed-good matches.
shell
curl -s "https://api.idmon.io/api/cross-market/venue-divergence?platform=kalshi&minSpreadPct=8" \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
[
  {
    "questionA": "Will Strait of Hormuz traffic return to normal by July 15?",
    "questionB": "Strait of Hormuz traffic returns to normal by July 15?",
    "platformA": "polymarket",
    "platformB": "kalshi",
    "priceA": 0.57,
    "priceB": 0.40,
    "spreadPp": 17.4,
    "netEdgePp": 13.4,
    "similarity": 0.83,
    "matchQuality": "unlabeled",
    "detectedAt": 1782125000000
  }
]
GET /api/overview Developer+

A single-request dashboard summary — alert and whale counts over 24 hours, and the number of currently active markets.

shell
curl -s https://api.idmon.io/api/overview \
  -H "Authorization: Bearer pmp_dev_your_key_here"
json — example response
{
  "alertCount24h": 28,
  "whaleCount24h": 18,
  "activeMarkets": 3142,
  "ts": "2026-06-19T11:04:00Z"
}

WebSocket

Available on Developer and Enterprise plans. Connect once to receive every alert as it fires — no polling, no batch lag.

Connect URL

url
wss://api.idmon.io/ws?key=<your-api-key>&types=volume_surge,whale_trade&minVolume=50000
Param Required Description
key Yes Your API key (Developer or Enterprise prefix).
types No Comma-separated alert types to filter. Omit to receive all types.
minVolume No Minimum 24h market volume (USD) to filter alerts.

Message types

json — connected (on open)
{ "type": "connected", "message": "Authenticated. Stream active." }
json — alert
{
  "type": "alert",
  "data": {
    "alertType": "whale_trade",
    "conditionId": "0xabc123...",
    "question": "Will the Fed cut rates in July 2026?",
    "category": "economics",
    "currentPrices": { "Yes": 0.62, "No": 0.38 },
    "priceChangePct": 4.8,
    "volume24h": 1240000,
    "message": "Whale bought $85K YES at 0.62",
    "timestamp": "2026-06-19T10:14:22Z"
  }
}
json — ping (every 30 s)
{ "type": "ping" }
Keepalive: The server sends a ping frame every 30 seconds. Clients should ignore it — no pong response is required. If you lose the connection, reconnect with the same URL.

Close codes

4001 Unauthorized — missing, invalid, or expired API key.
4003 Plan restriction — your tier does not include WebSocket access.
4008 Connection limit reached — you have too many concurrent WebSocket connections for your tier.

Node.js example

javascript
import WebSocket from 'ws';

const KEY = process.env.IDMON_API_KEY;
const url = `wss://api.idmon.io/ws?key=${KEY}&types=whale_trade,volume_surge&minVolume=50000`;

function connect() {
  const ws = new WebSocket(url);

  ws.on('open', () => {
    console.log('WebSocket open — waiting for alerts...');
  });

  ws.on('message', (raw) => {
    const msg = JSON.parse(raw.toString());

    if (msg.type === 'ping') return; // ignore keepalive

    if (msg.type === 'alert') {
      const { alertType, question, message, timestamp } = msg.data;
      console.log(`[${timestamp}] ${alertType}: ${question}`);
      console.log(`  ${message}`);
    }

    if (msg.type === 'connected') {
      console.log('Authenticated:', msg.message);
    }
  });

  ws.on('close', (code, reason) => {
    if (code === 4001) { console.error('Unauthorized — check your API key'); return; }
    if (code === 4003) { console.error('WebSocket not available on your plan'); return; }
    if (code === 4008) { console.error('Connection limit reached — reduce concurrent connections'); return; }
    // Reconnect on unexpected closure
    console.warn(`Closed (${code}): ${reason}. Reconnecting in 5s...`);
    setTimeout(connect, 5000);
  });

  ws.on('error', (err) => console.error('WS error:', err.message));
}

connect();

Webhooks

Available on Operator and above. We send signed HTTP POST requests to your endpoint within ~1.5 seconds of an alert — no polling required. Discord webhook URLs receive a Discord-formatted embeds payload automatically; all other URLs receive the generic JSON below.

Generic JSON payload

json
{
  "schema": 1,
  "event": "whale_trade",
  "id": "evt_01j9abc...",
  "ts": "2026-06-19T10:14:22Z",
  "conditionId": "0xabc123...",
  "data": {
    "question": "Will the Fed cut rates in July 2026?",
    "slug": "fed-rate-cut-july-2026",
    "category": "economics",
    "message": "Whale bought $85K YES at 0.62",
    "currentPrices": { "Yes": 0.62, "No": 0.38 },
    "previousPrices": { "Yes": 0.57, "No": 0.43 },
    "priceChangePct": 4.8,
    "volume24h": 1240000,
    "liquidity": 310000,
    "polymarketUrl": "https://polymarket.com/event/fed-rate-cut-july-2026"
  }
}

Request headers

Header Value / purpose
Content-Type application/json
X-PMP-Signature sha256=<hex> — HMAC-SHA256 of the raw request body with your webhook secret. Verify this before processing.
X-PMP-Delivery-Id Unique ID per delivery — use for idempotency (retries send the same ID).
User-Agent PMP-Webhooks/1.0

Signature verification

Always verify against the raw request body, not re-serialised JSON. Key ordering differences will break the HMAC check.
python
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = b"your_webhook_secret_here"

@app.route("/webhook", methods=["POST"])
def webhook():
    sig_header = request.headers.get("X-PMP-Signature", "")
    if not sig_header.startswith("sha256="):
        abort(400, "Missing signature")

    received_sig = sig_header[len("sha256="):]

    # Compute HMAC over the RAW body — do NOT re-serialise
    raw_body = request.get_data()
    expected_sig = hmac.new(WEBHOOK_SECRET, raw_body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected_sig, received_sig):
        abort(401, "Invalid signature")

    payload = request.get_json()
    event = payload["event"]
    print(f"Verified event: {event}")

    return "", 200  # respond 2xx quickly — processing can be async

Retry behaviour

If your endpoint is unavailable or returns a non-2xx response:

  • 5xx / timeout — exponential backoff, up to 4 retry attempts.
  • 429 — backoff respects your Retry-After response header.
  • Other 4xx — permanent failure; no retries. Respond 2xx quickly and handle processing asynchronously.

Use the X-PMP-Delivery-Id header to deduplicate retries on your side.

Rate limits

Exceeding any limit returns 429 Too Many Requests. Daily request counts reset at UTC midnight.

Tier REST WebSocket Requests / day Req / second Concurrent WS Bulk history
Operator Push only
Developer 10,000 10 5
Enterprise Unlimited 50 25

Operator tier receives data exclusively via push (signed webhooks / Discord embeds) — no REST or WebSocket access. Enterprise bulk history includes market snapshots (~8K rows/min) and 5-minute OHLCV aggregates.

Support

Need help?

Email us at [email protected] — we respond within 48 hours. Enterprise plans include priority support.

Email support

← Back to idmon.io