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.
Get started
Quickstart
Three steps from zero to live data.
Get your key
Email hello@idmon.io 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 accessMake your first call (Developer)
Once you have a key, fetch recent signal alerts:
curl -s https://api.idmon.io/api/alerts/recent?limit=5 \
-H "Authorization: Bearer pmp_dev_your_key_here"
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"
}
]
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.
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 |
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.
Returns service status, uptime, your tier, rate-limit headroom, and server memory. Use this to confirm connectivity and inspect your plan limits.
curl -s https://api.idmon.io/api/health \
-H "Authorization: Bearer pmp_dev_your_key_here"
{
"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"
}
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. |
curl -s "https://api.idmon.io/api/alerts/recent?limit=50&type=whale_trade" \
-H "Authorization: Bearer pmp_dev_your_key_here"
[
{
"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"
}
]
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. |
curl -s "https://api.idmon.io/api/alerts/counts?hours=24" \
-H "Authorization: Bearer pmp_dev_your_key_here"
{
"hours": 24,
"counts": {
"whale_trade": 18,
"volume_surge": 7,
"price_spike": 3
},
"since": "2026-06-18T11:00:00Z"
}
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. |
curl -s "https://api.idmon.io/api/whales/recent?limit=20" \
-H "Authorization: Bearer pmp_dev_your_key_here"
[
{
"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
}
]
Aggregate whale statistics — total all-time, mega-whale count, and rolling 24-hour volume.
curl -s https://api.idmon.io/api/whales/stats \
-H "Authorization: Bearer pmp_dev_your_key_here"
{
"totalWhaleAlerts": 4120,
"megaWhaleAlerts": 312,
"whaleAlerts24h": 18
}
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. |
curl -s "https://api.idmon.io/api/markets/top?limit=20&category=politics" \
-H "Authorization: Bearer pmp_dev_your_key_here"
[
{
"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/..."
}
]
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. |
curl -s "https://api.idmon.io/api/wallets/top?n=20" \
-H "Authorization: Bearer pmp_dev_your_key_here"
[
{
"walletAddress": "0x1a2b3c...",
"username": "sharpshooter",
"correctTrades": 84,
"totalTrades": 102,
"winRate": 0.824,
"currentStreak": 7,
"totalVolumeUsd": 540000,
"polymarketUrl": "https://polymarket.com/profile/0x1a2b3c..."
}
]
A single-request dashboard summary — alert and whale counts over 24 hours, and the number of currently active markets.
curl -s https://api.idmon.io/api/overview \
-H "Authorization: Bearer pmp_dev_your_key_here"
{
"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
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
{ "type": "connected", "message": "Authenticated. Stream active." }
{
"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"
}
}
{ "type": "ping" }
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
Node.js example
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
{
"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
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-Afterresponse 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 hello@idmon.io — we respond within 48 hours. Enterprise plans include priority support.