Webhook events

Every event Polywhaler can POST to your endpoint, what its data holds, and how to check that a delivery really came from us. Webhooks are part of the Quant plan; this page is open to everyone.

How delivery works#

Add an endpoint in the Developer portal (or with POST /v2/webhook-endpoints): an https URL on a public address, the event types it wants, and optional filters. Each event is then sent as one JSON POST.

  • Answer with any 2xx within 10 seconds. Anything else, including a timeout, is retried after 30 seconds, 2 minutes, 10 minutes, 1 hour, 3 hours, 6 hours and 12 hours, with some jitter: 8 attempts over about a day. A 429 or 503 with Retry-After is honoured up to an hour.
  • Redirects are never followed, and a URL that resolves to a private, loopback or cloud-metadata address is refused; neither is retried.
  • Every retry and every redelivery carries the same webhook-id, so store the ids you have handled and skip repeats. Deliveries can arrive out of order.
  • An endpoint that keeps failing (at least 10 failures in a row spread over more than three days, with no success since) or that answers 410 Gone twice an hour apart is disabled, and you get an email. Re-enable it in the portal and use Recover failed deliveries… to resend what it missed.

The event envelope#

Every body has the same envelope. data is the resource the type names, in the same shape the REST API returns it, so one parser serves both.

  • idstring

    The event id, evt_…: the same on every endpoint the event went to.

  • type"trade.whale"
  • apiVersion"v2"
  • createdAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • testboolean

    True on test sends (POST /v2/webhook-endpoints/{id}/test).

  • dataTrade

    One whale fill ($10k+ on Polymarket; Kalshi uses its own floors).

trade.whale example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.whale",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.42,
    "sizeShares": 50000,
    "amountUsd": 21000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    }
  }
}

Three headers come with it:

  • webhook-id: the delivery id, msg_…. The same on every attempt.
  • webhook-timestamp: when this attempt was signed, in Unix seconds.
  • webhook-signature: v1,<base64>, space-separated. While a secret is being rotated there are two, one per live secret; accept the delivery if either matches.

Verifying signatures#

Deliveries are signed to the Standard Webhooks spec: an HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the bytes your whsec_ secret encodes in base64 after the prefix. Reject a timestamp more than 5 minutes from your clock, so a captured delivery cannot be replayed later. The standardwebhooks libraries for Node and Python do all of this; the hand-written versions below do the same with no dependency.

The secret is shown once, when the endpoint is created. Rotate secret issues a new one and keeps the old one signing beside it for 24 hours by default, so you can deploy the new secret without dropping a delivery.

Node.js#

With standardwebhooks
// npm install standardwebhooks
import express from "express"
import { Webhook } from "standardwebhooks"

const wh = new Webhook(process.env.POLYWHALER_WEBHOOK_SECRET) // "whsec_..."
const app = express()

// The signature covers the exact bytes sent, so read the raw body.
app.post("/polywhaler", express.raw({ type: "application/json" }), (req, res) => {
  let event
  try {
    // Throws on a bad signature or a timestamp more than 5 minutes off.
    event = wh.verify(req.body.toString("utf8"), req.headers)
  } catch {
    return res.status(400).end()
  }
  // Retries reuse webhook-id: skip one you have already handled.
  if (alreadyHandled(req.headers["webhook-id"])) return res.status(204).end()
  queue(event) // answer within 10 seconds; do the work afterwards
  res.status(204).end()
})
Without a dependency
import crypto from "node:crypto"

export function verify(rawBody, headers, secret) {
  const id = headers["webhook-id"]
  const timestamp = headers["webhook-timestamp"]
  const signatures = headers["webhook-signature"]
  if (!id || !timestamp || !signatures) return false
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false

  const key = Buffer.from(secret.slice("whsec_".length), "base64")
  const expected = crypto
    .createHmac("sha256", key)
    .update(`${id}.${timestamp}.${rawBody}`)
    .digest()

  // Space-separated "v1,<base64>"; two of them while a secret rotates.
  return signatures.split(" ").some((entry) => {
    const [version, signature] = entry.split(",")
    if (version !== "v1" || !signature) return false
    const given = Buffer.from(signature, "base64")
    return given.length === expected.length && crypto.timingSafeEqual(given, expected)
  })
}

Python#

With standardwebhooks
# pip install standardwebhooks
import os
from flask import Flask, request
from standardwebhooks.webhooks import Webhook

wh = Webhook(os.environ["POLYWHALER_WEBHOOK_SECRET"])  # "whsec_..."
app = Flask(__name__)

@app.post("/polywhaler")
def receive():
    headers = {k.lower(): v for k, v in request.headers.items()}
    try:
        # Raises on a bad signature or a timestamp more than 5 minutes off.
        event = wh.verify(request.get_data(), headers)
    except Exception:
        return "", 400
    if already_handled(headers["webhook-id"]):  # retries reuse webhook-id
        return "", 204
    enqueue(event)  # answer within 10 seconds; do the work afterwards
    return "", 204
Without a dependency
import base64, hashlib, hmac, time

def verify(raw_body: bytes, headers: dict, secret: str) -> bool:
    msg_id = headers.get("webhook-id")
    timestamp = headers.get("webhook-timestamp")
    signatures = headers.get("webhook-signature", "")
    if not msg_id or not timestamp or abs(time.time() - int(timestamp)) > 300:
        return False

    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{timestamp}.".encode() + raw_body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()

    # Space-separated "v1,<base64>"; two of them while a secret rotates.
    return any(
        hmac.compare_digest(expected, entry.split(",", 1)[1])
        for entry in signatures.split()
        if entry.startswith("v1,")
    )

Filters#

Filters narrow what an endpoint receives: every key must match (AND), and a list matches any of its values (OR). A filter only applies to the types listed beside it, and an endpoint may not set one that applies to none of its types (400 filter_not_applicable). Numbers must be JSON numbers.

v1 endpoints#

Endpoints created before v2 keep working as they did until v1 is retired: the nine v1 event names, a pwsk_ secret, the X-Polywhaler-Signature: sha256=<hex> header (an HMAC of the body alone, with no timestamp), and 5 attempts. Each v2 event below names the v1 event it is also sent as, where there is one.

Verify a v1 delivery
import crypto from "node:crypto"

// v1 endpoints (secret pwsk_...): X-Polywhaler-Signature: sha256=<hex>
export function verifyV1(rawBody, header, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex")
  return header.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected))
}
  1. Open the v1 endpoint in the portal and choose Upgrade to v2. That creates a v2 endpoint on the same URL with the v1 events mapped to their v2 types, the filters in v2 form and a new whsec_ secret, shown once.
  2. Deploy the Standard Webhooks check with the new secret. Until you switch v1 off, each event arrives on both endpoints with the same event id (X-Polywhaler-Event-Id on v1, the envelope id on v2), so drop the duplicate by that id.
  3. Disable or delete the v1 endpoint.

Note

The full list of v1 changes is in Migrating from v1.

Trade events#

trade.whale#

A whale fill

A new fill of $10,000 or more on Polymarket, or a Kalshi fill over its whale floor. data is the trade as GET /v2/trades/{id} returns it.

data: Trade8 attemptsv2 only

Filters:venuesminAmountcategoriessidesminInsiderScorewallets

Show the payload53 fields
  • idstring

    Trade id: the transaction hash on Polymarket, kx_<tradeId> on Kalshi. Use with GET /v2/trades/{id}.

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • outcomestring | null

    The outcome bought or sold, e.g. Yes.

  • outcomeIndexinteger | null
  • priceProbabilitynumber

    Fill price, which is the implied probability of outcome.

  • sizeSharesnumber

    Shares (Polymarket) or contracts (Kalshi) filled.

  • amountUsdnumber

    Notional of the fill: sizeShares × priceProbability.

  • tradedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • marketobject

    The market the trade was in.

  • market.titlestring | null

    The market's question.

  • market.eventSlugstring | null

    Polymarket event slug, or the Kalshi event ticker.

  • market.marketSlugstring | null

    Polymarket market slug, or the Kalshi market ticker.

  • market.conditionIdstring | null

    Polymarket condition id. Null on Kalshi.

  • market.assetstring | null

    Polymarket outcome token id. Null on Kalshi.

  • market.tickerstring | null

    Kalshi market ticker. Null on Polymarket.

  • market.iconstring | null
  • market.categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • market.tagsany[]

    Polymarket event tags, as Polymarket returns them.

  • market.endsAtstring (date-time) | null

    Scheduled end of the market, when known.

  • venue"polymarket" | "kalshi"
  • transactionHashstring | null

    An on-chain transaction hash, lowercase.

  • walletstring | null

    A Polygon wallet address, always lowercase.

  • traderobject

    Display identity of the wallet's Polymarket account.

  • trader.namestring | null

    Polymarket display name, when set.

  • trader.pseudonymstring | null

    Polymarket's generated pseudonym.

  • trader.imagestring | null

    Profile image URL.

  • insiderobject | null
  • insider.scorenumber | null

    Insider-risk score, 0..100: above 40 is medium, above 70 high. Null when the trade has not been scored (only Polymarket buys are).

  • insider.breakdownobject

    The insider score's factors, in points. Each factor is capped, and together they add up to score, which is capped at 100 (sports trades are capped lower, below the high band).

  • insider.breakdown.convictionnumber | null

    A large position at long odds. Points, at most 35.

  • insider.breakdown.priceImpactnumber | null

    How far the trade moved the price. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.tradeSizenumber | null

    The trade's size on its own. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.marketDominancenumber | null

    The trade's size against the market's trading over the previous 24 hours. Points, at most 20.

  • insider.breakdown.timingnumber | null

    How close to the market's resolution the trade came, or a large early position on a distant event. Points, at most 10.

  • insider.breakdown.walletAgenumber | null

    How new the wallet was when it traded. Points, at most 15.

  • insider.breakdown.contextnumber | null

    How much the market's kind of event lends itself to inside knowledge. Points, at most 20.

  • insider.detailsobject | null

    The full scoring record (GET /v2/trades/{id} only). Its fields may grow; treat it as informational.

  • smartMoneyobject | null

    Present with include=smartMoney: null when the wallet is not on the board.

  • smartMoney.rankinteger | null

    The wallet's Smart Money rank (1 = best), null while provisional.

  • smartMoney.scorenumber

    The wallet's smoothed Smart Money Score.

  • smartMoney.tierenum

    Badge band: genius 80+ (methodology 4 also needs a minimum of realized edge in dollars), smart 60+, average 40+, naive below.

  • smartMoney.styleenum | null

    Trading style; null under methodology 3, which has none.

    One oflong-shotbalancedfavoriteunknown

  • smartMoney.methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • resolutionobject | null
  • resolution.statusenum

    One ofwinlosspendingcancelledinvalid

  • resolution.winningOutcomestring | null
  • resolution.entryPricenumber | null
  • resolution.exitPricenumber | null
  • resolution.pnlUsdnumber | null
  • resolution.roinumber | null
  • resolution.resolvedAtstring (date-time) | null
  • resolution.holdSecondsinteger | null
  • resolution.vindicatedboolean

    A high-insider-score trade that won.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.whale",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.42,
    "sizeShares": 50000,
    "amountUsd": 21000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    }
  }
}

trade.smart_money#

A fill by a top Smart Money wallet

A whale fill by a wallet ranked on the Smart Money board (by default the top 100; set maxRank). Polymarket only. data is the trade with the wallet's standing.

data: SmartMoneyTrade8 attemptsv2 only

Filters:venuesminAmountcategoriessidesminInsiderScoremaxRankminScorewallets

Show the payload53 fields
  • idstring

    Trade id: the transaction hash on Polymarket, kx_<tradeId> on Kalshi. Use with GET /v2/trades/{id}.

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • outcomestring | null

    The outcome bought or sold, e.g. Yes.

  • outcomeIndexinteger | null
  • priceProbabilitynumber

    Fill price, which is the implied probability of outcome.

  • sizeSharesnumber

    Shares (Polymarket) or contracts (Kalshi) filled.

  • amountUsdnumber

    Notional of the fill: sizeShares × priceProbability.

  • tradedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • marketobject

    The market the trade was in.

  • market.titlestring | null

    The market's question.

  • market.eventSlugstring | null

    Polymarket event slug, or the Kalshi event ticker.

  • market.marketSlugstring | null

    Polymarket market slug, or the Kalshi market ticker.

  • market.conditionIdstring | null

    Polymarket condition id. Null on Kalshi.

  • market.assetstring | null

    Polymarket outcome token id. Null on Kalshi.

  • market.tickerstring | null

    Kalshi market ticker. Null on Polymarket.

  • market.iconstring | null
  • market.categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • market.tagsany[]

    Polymarket event tags, as Polymarket returns them.

  • market.endsAtstring (date-time) | null

    Scheduled end of the market, when known.

  • venue"polymarket"
  • transactionHashstring

    An on-chain transaction hash, lowercase.

  • walletstring

    A Polygon wallet address, always lowercase.

  • traderobject

    Display identity of the wallet's Polymarket account.

  • trader.namestring | null

    Polymarket display name, when set.

  • trader.pseudonymstring | null

    Polymarket's generated pseudonym.

  • trader.imagestring | null

    Profile image URL.

  • insiderobject | null
  • insider.scorenumber | null

    Insider-risk score, 0..100: above 40 is medium, above 70 high. Null when the trade has not been scored (only Polymarket buys are).

  • insider.breakdownobject

    The insider score's factors, in points. Each factor is capped, and together they add up to score, which is capped at 100 (sports trades are capped lower, below the high band).

  • insider.breakdown.convictionnumber | null

    A large position at long odds. Points, at most 35.

  • insider.breakdown.priceImpactnumber | null

    How far the trade moved the price. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.tradeSizenumber | null

    The trade's size on its own. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.marketDominancenumber | null

    The trade's size against the market's trading over the previous 24 hours. Points, at most 20.

  • insider.breakdown.timingnumber | null

    How close to the market's resolution the trade came, or a large early position on a distant event. Points, at most 10.

  • insider.breakdown.walletAgenumber | null

    How new the wallet was when it traded. Points, at most 15.

  • insider.breakdown.contextnumber | null

    How much the market's kind of event lends itself to inside knowledge. Points, at most 20.

  • insider.detailsobject | null

    The full scoring record (GET /v2/trades/{id} only). Its fields may grow; treat it as informational.

  • smartMoneyobject

    The trading wallet's Smart Money standing at request time.

  • smartMoney.rankinteger | null

    The wallet's Smart Money rank (1 = best), null while provisional.

  • smartMoney.scorenumber

    The wallet's smoothed Smart Money Score.

  • smartMoney.tierenum

    Badge band: genius 80+ (methodology 4 also needs a minimum of realized edge in dollars), smart 60+, average 40+, naive below.

  • smartMoney.styleenum | null

    Trading style; null under methodology 3, which has none.

    One oflong-shotbalancedfavoriteunknown

  • smartMoney.methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • resolutionobject | null
  • resolution.statusenum

    One ofwinlosspendingcancelledinvalid

  • resolution.winningOutcomestring | null
  • resolution.entryPricenumber | null
  • resolution.exitPricenumber | null
  • resolution.pnlUsdnumber | null
  • resolution.roinumber | null
  • resolution.resolvedAtstring (date-time) | null
  • resolution.holdSecondsinteger | null
  • resolution.vindicatedboolean

    A high-insider-score trade that won.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.smart_money",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.42,
    "sizeShares": 50000,
    "amountUsd": 21000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    },
    "smartMoney": {
      "rank": 7,
      "score": 83.1,
      "tier": "genius",
      "style": null,
      "methodologyVersion": 3
    }
  }
}

trade.followed_wallet#

A fill by a wallet on your watchlist

A new fill by a wallet you follow. Sent only to your own endpoints.

data: TradeYour endpoints only8 attemptsv1: trade.followed_wallet

Filters:minAmountcategoriessidesminInsiderScorewallets

Show the payload53 fields
  • idstring

    Trade id: the transaction hash on Polymarket, kx_<tradeId> on Kalshi. Use with GET /v2/trades/{id}.

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • outcomestring | null

    The outcome bought or sold, e.g. Yes.

  • outcomeIndexinteger | null
  • priceProbabilitynumber

    Fill price, which is the implied probability of outcome.

  • sizeSharesnumber

    Shares (Polymarket) or contracts (Kalshi) filled.

  • amountUsdnumber

    Notional of the fill: sizeShares × priceProbability.

  • tradedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • marketobject

    The market the trade was in.

  • market.titlestring | null

    The market's question.

  • market.eventSlugstring | null

    Polymarket event slug, or the Kalshi event ticker.

  • market.marketSlugstring | null

    Polymarket market slug, or the Kalshi market ticker.

  • market.conditionIdstring | null

    Polymarket condition id. Null on Kalshi.

  • market.assetstring | null

    Polymarket outcome token id. Null on Kalshi.

  • market.tickerstring | null

    Kalshi market ticker. Null on Polymarket.

  • market.iconstring | null
  • market.categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • market.tagsany[]

    Polymarket event tags, as Polymarket returns them.

  • market.endsAtstring (date-time) | null

    Scheduled end of the market, when known.

  • venue"polymarket" | "kalshi"
  • transactionHashstring | null

    An on-chain transaction hash, lowercase.

  • walletstring | null

    A Polygon wallet address, always lowercase.

  • traderobject

    Display identity of the wallet's Polymarket account.

  • trader.namestring | null

    Polymarket display name, when set.

  • trader.pseudonymstring | null

    Polymarket's generated pseudonym.

  • trader.imagestring | null

    Profile image URL.

  • insiderobject | null
  • insider.scorenumber | null

    Insider-risk score, 0..100: above 40 is medium, above 70 high. Null when the trade has not been scored (only Polymarket buys are).

  • insider.breakdownobject

    The insider score's factors, in points. Each factor is capped, and together they add up to score, which is capped at 100 (sports trades are capped lower, below the high band).

  • insider.breakdown.convictionnumber | null

    A large position at long odds. Points, at most 35.

  • insider.breakdown.priceImpactnumber | null

    How far the trade moved the price. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.tradeSizenumber | null

    The trade's size on its own. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.marketDominancenumber | null

    The trade's size against the market's trading over the previous 24 hours. Points, at most 20.

  • insider.breakdown.timingnumber | null

    How close to the market's resolution the trade came, or a large early position on a distant event. Points, at most 10.

  • insider.breakdown.walletAgenumber | null

    How new the wallet was when it traded. Points, at most 15.

  • insider.breakdown.contextnumber | null

    How much the market's kind of event lends itself to inside knowledge. Points, at most 20.

  • insider.detailsobject | null

    The full scoring record (GET /v2/trades/{id} only). Its fields may grow; treat it as informational.

  • smartMoneyobject | null

    Present with include=smartMoney: null when the wallet is not on the board.

  • smartMoney.rankinteger | null

    The wallet's Smart Money rank (1 = best), null while provisional.

  • smartMoney.scorenumber

    The wallet's smoothed Smart Money Score.

  • smartMoney.tierenum

    Badge band: genius 80+ (methodology 4 also needs a minimum of realized edge in dollars), smart 60+, average 40+, naive below.

  • smartMoney.styleenum | null

    Trading style; null under methodology 3, which has none.

    One oflong-shotbalancedfavoriteunknown

  • smartMoney.methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • resolutionobject | null
  • resolution.statusenum

    One ofwinlosspendingcancelledinvalid

  • resolution.winningOutcomestring | null
  • resolution.entryPricenumber | null
  • resolution.exitPricenumber | null
  • resolution.pnlUsdnumber | null
  • resolution.roinumber | null
  • resolution.resolvedAtstring (date-time) | null
  • resolution.holdSecondsinteger | null
  • resolution.vindicatedboolean

    A high-insider-score trade that won.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.followed_wallet",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.42,
    "sizeShares": 50000,
    "amountUsd": 21000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    }
  }
}

trade.insider_flagged#

A fill with a high insider-risk score

A new Polymarket buy whose insider-risk score is 70 or more (only buys are scored). Badges and filters call a score high only above 70, so a fill at exactly 70 is sent here but reads as medium. (v1: trade.high_insider.)

data: Trade8 attemptsv1: trade.high_insider

Filters:minAmountcategoriessidesminInsiderScorewallets

Show the payload53 fields
  • idstring

    Trade id: the transaction hash on Polymarket, kx_<tradeId> on Kalshi. Use with GET /v2/trades/{id}.

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • outcomestring | null

    The outcome bought or sold, e.g. Yes.

  • outcomeIndexinteger | null
  • priceProbabilitynumber

    Fill price, which is the implied probability of outcome.

  • sizeSharesnumber

    Shares (Polymarket) or contracts (Kalshi) filled.

  • amountUsdnumber

    Notional of the fill: sizeShares × priceProbability.

  • tradedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • marketobject

    The market the trade was in.

  • market.titlestring | null

    The market's question.

  • market.eventSlugstring | null

    Polymarket event slug, or the Kalshi event ticker.

  • market.marketSlugstring | null

    Polymarket market slug, or the Kalshi market ticker.

  • market.conditionIdstring | null

    Polymarket condition id. Null on Kalshi.

  • market.assetstring | null

    Polymarket outcome token id. Null on Kalshi.

  • market.tickerstring | null

    Kalshi market ticker. Null on Polymarket.

  • market.iconstring | null
  • market.categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • market.tagsany[]

    Polymarket event tags, as Polymarket returns them.

  • market.endsAtstring (date-time) | null

    Scheduled end of the market, when known.

  • venue"polymarket" | "kalshi"
  • transactionHashstring | null

    An on-chain transaction hash, lowercase.

  • walletstring | null

    A Polygon wallet address, always lowercase.

  • traderobject

    Display identity of the wallet's Polymarket account.

  • trader.namestring | null

    Polymarket display name, when set.

  • trader.pseudonymstring | null

    Polymarket's generated pseudonym.

  • trader.imagestring | null

    Profile image URL.

  • insiderobject | null
  • insider.scorenumber | null

    Insider-risk score, 0..100: above 40 is medium, above 70 high. Null when the trade has not been scored (only Polymarket buys are).

  • insider.breakdownobject

    The insider score's factors, in points. Each factor is capped, and together they add up to score, which is capped at 100 (sports trades are capped lower, below the high band).

  • insider.breakdown.convictionnumber | null

    A large position at long odds. Points, at most 35.

  • insider.breakdown.priceImpactnumber | null

    How far the trade moved the price. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.tradeSizenumber | null

    The trade's size on its own. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.marketDominancenumber | null

    The trade's size against the market's trading over the previous 24 hours. Points, at most 20.

  • insider.breakdown.timingnumber | null

    How close to the market's resolution the trade came, or a large early position on a distant event. Points, at most 10.

  • insider.breakdown.walletAgenumber | null

    How new the wallet was when it traded. Points, at most 15.

  • insider.breakdown.contextnumber | null

    How much the market's kind of event lends itself to inside knowledge. Points, at most 20.

  • insider.detailsobject | null

    The full scoring record (GET /v2/trades/{id} only). Its fields may grow; treat it as informational.

  • smartMoneyobject | null

    Present with include=smartMoney: null when the wallet is not on the board.

  • smartMoney.rankinteger | null

    The wallet's Smart Money rank (1 = best), null while provisional.

  • smartMoney.scorenumber

    The wallet's smoothed Smart Money Score.

  • smartMoney.tierenum

    Badge band: genius 80+ (methodology 4 also needs a minimum of realized edge in dollars), smart 60+, average 40+, naive below.

  • smartMoney.styleenum | null

    Trading style; null under methodology 3, which has none.

    One oflong-shotbalancedfavoriteunknown

  • smartMoney.methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • resolutionobject | null
  • resolution.statusenum

    One ofwinlosspendingcancelledinvalid

  • resolution.winningOutcomestring | null
  • resolution.entryPricenumber | null
  • resolution.exitPricenumber | null
  • resolution.pnlUsdnumber | null
  • resolution.roinumber | null
  • resolution.resolvedAtstring (date-time) | null
  • resolution.holdSecondsinteger | null
  • resolution.vindicatedboolean

    A high-insider-score trade that won.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.insider_flagged",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.42,
    "sizeShares": 50000,
    "amountUsd": 21000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    }
  }
}

trade.vindicated#

A flagged low-odds trade won

A high-insider-score fill bought at low odds whose market just resolved in its favour. data includes resolution.

data: Trade8 attemptsv1: trade.vindicated

Filters:minAmountcategoriessidesminInsiderScorewallets

Show the payload53 fields
  • idstring

    Trade id: the transaction hash on Polymarket, kx_<tradeId> on Kalshi. Use with GET /v2/trades/{id}.

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • outcomestring | null

    The outcome bought or sold, e.g. Yes.

  • outcomeIndexinteger | null
  • priceProbabilitynumber

    Fill price, which is the implied probability of outcome.

  • sizeSharesnumber

    Shares (Polymarket) or contracts (Kalshi) filled.

  • amountUsdnumber

    Notional of the fill: sizeShares × priceProbability.

  • tradedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • marketobject

    The market the trade was in.

  • market.titlestring | null

    The market's question.

  • market.eventSlugstring | null

    Polymarket event slug, or the Kalshi event ticker.

  • market.marketSlugstring | null

    Polymarket market slug, or the Kalshi market ticker.

  • market.conditionIdstring | null

    Polymarket condition id. Null on Kalshi.

  • market.assetstring | null

    Polymarket outcome token id. Null on Kalshi.

  • market.tickerstring | null

    Kalshi market ticker. Null on Polymarket.

  • market.iconstring | null
  • market.categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • market.tagsany[]

    Polymarket event tags, as Polymarket returns them.

  • market.endsAtstring (date-time) | null

    Scheduled end of the market, when known.

  • venue"polymarket" | "kalshi"
  • transactionHashstring | null

    An on-chain transaction hash, lowercase.

  • walletstring | null

    A Polygon wallet address, always lowercase.

  • traderobject

    Display identity of the wallet's Polymarket account.

  • trader.namestring | null

    Polymarket display name, when set.

  • trader.pseudonymstring | null

    Polymarket's generated pseudonym.

  • trader.imagestring | null

    Profile image URL.

  • insiderobject | null
  • insider.scorenumber | null

    Insider-risk score, 0..100: above 40 is medium, above 70 high. Null when the trade has not been scored (only Polymarket buys are).

  • insider.breakdownobject

    The insider score's factors, in points. Each factor is capped, and together they add up to score, which is capped at 100 (sports trades are capped lower, below the high band).

  • insider.breakdown.convictionnumber | null

    A large position at long odds. Points, at most 35.

  • insider.breakdown.priceImpactnumber | null

    How far the trade moved the price. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.tradeSizenumber | null

    The trade's size on its own. No longer scored: 0 on trades scored now, kept for older trades.

  • insider.breakdown.marketDominancenumber | null

    The trade's size against the market's trading over the previous 24 hours. Points, at most 20.

  • insider.breakdown.timingnumber | null

    How close to the market's resolution the trade came, or a large early position on a distant event. Points, at most 10.

  • insider.breakdown.walletAgenumber | null

    How new the wallet was when it traded. Points, at most 15.

  • insider.breakdown.contextnumber | null

    How much the market's kind of event lends itself to inside knowledge. Points, at most 20.

  • insider.detailsobject | null

    The full scoring record (GET /v2/trades/{id} only). Its fields may grow; treat it as informational.

  • smartMoneyobject | null

    Present with include=smartMoney: null when the wallet is not on the board.

  • smartMoney.rankinteger | null

    The wallet's Smart Money rank (1 = best), null while provisional.

  • smartMoney.scorenumber

    The wallet's smoothed Smart Money Score.

  • smartMoney.tierenum

    Badge band: genius 80+ (methodology 4 also needs a minimum of realized edge in dollars), smart 60+, average 40+, naive below.

  • smartMoney.styleenum | null

    Trading style; null under methodology 3, which has none.

    One oflong-shotbalancedfavoriteunknown

  • smartMoney.methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • resolutionobject | null
  • resolution.statusenum

    One ofwinlosspendingcancelledinvalid

  • resolution.winningOutcomestring | null
  • resolution.entryPricenumber | null
  • resolution.exitPricenumber | null
  • resolution.pnlUsdnumber | null
  • resolution.roinumber | null
  • resolution.resolvedAtstring (date-time) | null
  • resolution.holdSecondsinteger | null
  • resolution.vindicatedboolean

    A high-insider-score trade that won.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "trade.vindicated",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "venue": "polymarket",
    "transactionHash": "0x6f1c3d2b8a9e4f5061728394a5b6c7d8e9f0011223344556677889aabbccddee",
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "pseudonym": "Sample-Heron",
      "image": null
    },
    "side": "BUY",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "priceProbability": 0.04,
    "sizeShares": 50000,
    "amountUsd": 2000,
    "tradedAt": "2026-10-09T14:03:27.000Z",
    "market": {
      "title": "Will BTC close above $130k on Oct 31?",
      "eventSlug": "bitcoin-above-on-october-31",
      "marketSlug": "bitcoin-above-130k-on-october-31",
      "conditionId": "0x1d4e9a",
      "asset": "51234567890",
      "ticker": null,
      "icon": "https://polymarket-upload.s3.amazonaws.com/btc.png",
      "category": "crypto",
      "tags": [
        {
          "id": "21",
          "label": "Crypto",
          "slug": "crypto"
        }
      ],
      "endsAt": "2026-10-31T16:00:00.000Z"
    },
    "insider": {
      "score": 82,
      "breakdown": {
        "conviction": 35,
        "priceImpact": 0,
        "tradeSize": 0,
        "marketDominance": 15,
        "timing": 8,
        "walletAge": 4,
        "context": 20
      }
    },
    "resolution": {
      "status": "win",
      "winningOutcome": "Yes",
      "entryPrice": 0.04,
      "exitPrice": 1,
      "pnlUsd": 48000,
      "roi": 24,
      "resolvedAt": "2026-10-31T17:02:11.000Z",
      "holdSeconds": 1900000,
      "vindicated": true
    }
  }
}

Wallet and leaderboard events#

wallet.rank_changed#

A wallet's Smart Money rank moved

From the daily board snapshot (about 04:10 UTC): a wallet in the top 100 (or on your watchlist) moved at least minRankDelta places, or entered or left the top 100. Not sent on a day the methodology changed.

data: WalletRankChange8 attemptsv2 only

Filters:walletswalletScopeminRankDelta

Show the payload14 fields
  • walletstring

    A Polygon wallet address, always lowercase.

  • traderobject

    The wallet's display name and image, when known.

  • trader.namestring | null
  • trader.imagestring | null
  • snapshotDatestring (date)

    The daily snapshot compared (UTC).

  • previousSnapshotDatestring (date) | null

    The snapshot it was compared with.

  • methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • inTop100boolean

    Ranked in the top 100 on snapshotDate.

  • wasInTop100boolean

    Ranked in the top 100 on previousSnapshotDate.

  • rankinteger | null

    Rank on snapshotDate; null when the wallet dropped off the board.

  • previousRankinteger | null
  • deltainteger | null

    Places moved: positive is up (previousRank - rank).

  • enteredTop100boolean
  • exitedTop100boolean
Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "wallet.rank_changed",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "image": null
    },
    "snapshotDate": "2026-10-09",
    "previousSnapshotDate": "2026-10-08",
    "methodologyVersion": 3,
    "inTop100": true,
    "wasInTop100": true,
    "rank": 7,
    "previousRank": 31,
    "delta": 24,
    "enteredTop100": false,
    "exitedTop100": false
  }
}

wallet.score_changed#

A wallet's Smart Money Score changed

From the daily board snapshot: a wallet's score moved at least minScoreDelta points. Not sent on a day the methodology changed.

data: WalletScoreChange8 attemptsv2 only

Filters:walletswalletScopeminScoreDelta

Show the payload14 fields
  • walletstring

    A Polygon wallet address, always lowercase.

  • traderobject

    The wallet's display name and image, when known.

  • trader.namestring | null
  • trader.imagestring | null
  • snapshotDatestring (date)

    The daily snapshot compared (UTC).

  • previousSnapshotDatestring (date) | null

    The snapshot it was compared with.

  • methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • inTop100boolean

    Ranked in the top 100 on snapshotDate.

  • wasInTop100boolean

    Ranked in the top 100 on previousSnapshotDate.

  • scorenumber | null
  • previousScorenumber | null
  • deltanumber | null

    score - previousScore.

  • tierenum | null

    One ofgeniussmartaveragenaive

  • previousTierenum | null

    One ofgeniussmartaveragenaive

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "wallet.score_changed",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
    "trader": {
      "name": "sample-whale",
      "image": null
    },
    "snapshotDate": "2026-10-09",
    "previousSnapshotDate": "2026-10-08",
    "methodologyVersion": 3,
    "inTop100": true,
    "wasInTop100": true,
    "score": 83.1,
    "previousScore": 76.4,
    "delta": 6.7,
    "tier": "genius",
    "previousTier": "smart"
  }
}

leaderboard.updated#

The daily Smart Money board

Once a day after the snapshot: the top 100, and the wallets that entered or left it. methodologyChanged is true on the day a new methodology took over.

data: LeaderboardUpdate8 attemptsv2 only
Show the payload12 fields
  • snapshotDatestring (date)

    A UTC calendar day, YYYY-MM-DD.

  • previousSnapshotDatestring (date) | null
  • methodologyVersioninteger

    The Smart Money Score methodology version that produced this score. GET /v2/methodology/{version} returns its specification.

  • methodologyChangedboolean

    True when the two snapshots were scored by different methodologies. Per-wallet change events are not sent that day.

  • entriesobject[]

    The top 100, best first.

  • entries[].rankinteger
  • entries[].previousRankinteger | null
  • entries[].walletstring

    A Polygon wallet address, always lowercase.

  • entries[].namestring | null
  • entries[].scorenumber | null
  • enteredstring[]

    Wallets in today's top 100 that were not in the previous one.

  • exitedstring[]

    Wallets in the previous top 100 that are not in today's.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "leaderboard.updated",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "snapshotDate": "2026-10-09",
    "previousSnapshotDate": "2026-10-08",
    "methodologyVersion": 3,
    "methodologyChanged": false,
    "entries": [
      {
        "rank": 7,
        "previousRank": 31,
        "wallet": "0x5c1d7e93a0b4f26c8e1a9d3b7f05c2e4a6b8d913",
        "name": "sample-whale",
        "score": 83.1
      }
    ],
    "entered": [],
    "exited": [
      "0x0000000000000000000000000000000000000004"
    ]
  }
}

Signal events#

cluster.detected#

Coordinated wallets detected

A new cluster of wallets trading in coordination. confidence is 0..1.

data: Cluster8 attemptsv1: cluster.detected

Filters:minConfidence

Show the payload12 fields
  • clusterIdstring
  • walletsstring[]
  • sizeinteger
  • detectionMethodenum

    One oftiming_correlationoutcome_correlationfunding_sourcemulti_factor

  • confidencenumber

    Detection confidence, 0..1.

  • outcomeAlignmentnumber | null

    Share of shared markets where the wallets chose the same outcome.

  • coordinatedTradeCountinteger
  • firstCoordinatedTradeAtstring (date-time) | null
  • lastCoordinatedTradeAtstring (date-time) | null
  • activeboolean
  • flaggedForReviewboolean
  • detectedAtstring (date-time) | null
Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "cluster.detected",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "clusterId": "c-timing-20261009-01",
    "wallets": [
      "0x0000000000000000000000000000000000000001",
      "0x0000000000000000000000000000000000000002",
      "0x0000000000000000000000000000000000000003"
    ],
    "size": 3,
    "detectionMethod": "timing_correlation",
    "confidence": 0.91,
    "outcomeAlignment": 0.885,
    "coordinatedTradeCount": 14,
    "firstCoordinatedTradeAt": "2026-10-08T10:00:00.000Z",
    "lastCoordinatedTradeAt": "2026-10-09T09:30:00.000Z",
    "active": true,
    "flaggedForReview": false,
    "detectedAt": "2026-10-09T12:00:00.123Z"
  }
}

consensus.detected#

Your wallets converged

Several wallets on your watchlist took the same position within the hour. Sent only to your own endpoints.

data: ConsensusGroupYour endpoints only8 attemptsv1: consensus.detected

Filters:minAmountsidesminWhales

Show the payload18 fields
  • positionKeystring

    Stable id of the converged position.

  • titlestring | null
  • outcomestring | null
  • outcomeIndexinteger | null
  • eventSlugstring | null
  • marketSlugstring | null
  • iconstring | null
  • categoryenum | null

    One ofcryptopoliticseconomygeopoliticstechculturesciencesportsesportsothermarkets

  • sideenum

    Taker side of the fill.

    One ofBUYSELL

  • whaleCountinteger
  • valueUsdnumber

    Combined notional across the converging wallets.

  • lastTradeAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • whalesobject[]
  • whales[].walletstring

    A Polygon wallet address, always lowercase.

  • whales[].namestring | null
  • whales[].imagestring | null
  • whales[].valueUsdnumber

    US dollars.

  • whales[].lastTradeAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "consensus.detected",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "positionKey": "bitcoin-above-on-october-31|Yes|BUY",
    "title": "Will BTC close above $130k on Oct 31?",
    "outcome": "Yes",
    "outcomeIndex": 0,
    "eventSlug": "bitcoin-above-on-october-31",
    "marketSlug": "bitcoin-above-130k-on-october-31",
    "icon": null,
    "category": "crypto",
    "side": "BUY",
    "whaleCount": 3,
    "valueUsd": 68000,
    "lastTradeAt": "2026-10-09T14:03:27.000Z",
    "whales": [
      {
        "wallet": "0x0000000000000000000000000000000000000001",
        "name": "alpha",
        "image": null,
        "valueUsd": 30000,
        "lastTradeAt": "2026-10-09T12:46:40.000Z"
      },
      {
        "wallet": "0x0000000000000000000000000000000000000002",
        "name": null,
        "image": null,
        "valueUsd": 20000,
        "lastTradeAt": "2026-10-09T13:20:00.000Z"
      },
      {
        "wallet": "0x0000000000000000000000000000000000000003",
        "name": "gamma",
        "image": "https://example.com/g.png",
        "valueUsd": 18000,
        "lastTradeAt": "2026-10-09T14:03:27.000Z"
      }
    ]
  }
}

black_swan.status_changed#

The Black Swan radar changed status

The radar moved between calm, ripples, storm and black_swan. (v1: black_swan.changed.)

data: BlackSwanStatusChange8 attemptsv1: black_swan.changed
Show the payload22 fields
  • indexnumber

    Geopolitical risk index, 0..100.

  • statusenum

    One ofcalmripplesstormblack_swan

  • statusLabelstring
  • statusDescriptionstring
  • componentsobject
  • components.probabilitynumber | null
  • components.insidernumber | null
  • components.resolvednumber | null
  • highestRiskMarketobject | null
  • highestRiskMarket.slugstring
  • highestRiskMarket.titlestring
  • highestRiskMarket.probabilitynumber

    A rate on 0..1.

  • highestRiskMarket.categorystring | null
  • highestRiskMarket.aiScorenumber | null
  • trackedMarketCountinteger
  • insiderActivityobject | null
  • insiderActivity.volumeUsdnumber

    US dollars.

  • insiderActivity.averageScorenumber | null
  • insiderActivity.tradeCountinteger
  • insiderActivity.yesBuyVolumeUsdnumber

    US dollars.

  • updatedAtstring (date-time) | null
  • previousStatusenum | null

    One ofcalmripplesstormblack_swan

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "black_swan.status_changed",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "index": 41.5,
    "status": "ripples",
    "statusLabel": "Ripples",
    "statusDescription": "Some unusual activity in geopolitical markets.",
    "components": {
      "probability": 30,
      "insider": 55,
      "resolved": 10
    },
    "highestRiskMarket": {
      "slug": "strike-on-x",
      "title": "Military strike on X by Oct 31?",
      "probability": 0.12,
      "category": "geopolitics",
      "aiScore": 73
    },
    "trackedMarketCount": 42,
    "insiderActivity": {
      "volumeUsd": 250000,
      "averageScore": 66,
      "tradeCount": 9,
      "yesBuyVolumeUsd": 180000
    },
    "updatedAt": "2026-10-09T14:00:00.000Z",
    "previousStatus": "calm"
  }
}

oracle.edition_published#

A new edition of The Oracle

The daily edition was published. (v1: oracle.published.)

data: OracleEdition8 attemptsv1: oracle.published
Show the payload23 fields
  • idstring
  • datestring (date)
  • volumeNumberinteger
  • publishedAtstring (date-time) | null
  • articlesobject[]
  • articles[].eventSlugstring
  • articles[].categorystring
  • articles[].headlinestring
  • articles[].ledestring
  • articles[].bodystring
  • articles[].predictedOutcomestring | null
  • articles[].confidencenumber | null
  • articles[].imageUrlstring | null
  • articles[].resolvesAtstring (date-time) | null
  • articles[].evidenceobject | null
  • articles[].evidence.volumeUsdnumber | null
  • articles[].evidence.tradeCountinteger | null
  • articles[].evidence.buyVolumeUsdnumber | null
  • articles[].evidence.sellVolumeUsdnumber | null
  • articles[].evidence.avgInsiderScorenumber | null
  • articles[].evidence.maxInsiderScorenumber | null
  • articles[].evidence.dominantSideenum | null

    One ofBUYSELL

  • articles[].evidence.avgProbabilitynumber | null
Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "oracle.edition_published",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "6b0b8a8e-6e0d-4f7a-9d2e-0c1f2a3b4c5d",
    "date": "2026-10-09",
    "volumeNumber": 128,
    "publishedAt": "2026-10-09T11:00:04.512Z",
    "articles": [
      {
        "eventSlug": "bitcoin-above-on-october-31",
        "category": "crypto",
        "headline": "Whales pile into $130k BTC calls",
        "lede": "Three wallets bought $68k of Yes in an hour.",
        "body": "Body text.",
        "predictedOutcome": "Yes",
        "confidence": 0.62,
        "imageUrl": null,
        "resolvesAt": "2026-10-31T16:00:00.000Z",
        "evidence": {
          "volumeUsd": 68000,
          "tradeCount": 3,
          "buyVolumeUsd": 68000,
          "sellVolumeUsd": 0,
          "avgInsiderScore": 41,
          "maxInsiderScore": 70,
          "dominantSide": "BUY",
          "avgProbability": 0.42
        }
      },
      {
        "eventSlug": "fed-decision-in-october",
        "category": "economics",
        "headline": "Smart money fades a cut",
        "lede": "Big No buying ahead of the meeting.",
        "body": "Body text.",
        "predictedOutcome": "No",
        "confidence": 0.55,
        "imageUrl": null,
        "resolvesAt": null,
        "evidence": null
      }
    ]
  }
}

Forecast events#

btc_forecast.updated#

A new BTC forecast run

The hourly BTC price forecast was recomputed. data is the run as GET /v2/forecasts/btc returns it, with the modelVersion that produced it.

data: BtcForecast8 attemptsv1: btc_forecast.updated
Show the payload50 fields
  • runAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • spotUsdnumber

    US dollars.

  • spotSourcestring
  • modelVersionstring

    The model that produced the run, e.g. btc-forecast/1.1.0. Methods change between versions, so segment backtests by it. The full specification and version history are in the Developer portal for Quant subscribers: polywhaler.com/developer/methodology#bitcoin-forecast.

  • marketCountinteger
  • confidencenumber

    Quality of the evidence behind the run, 0..1: the horizons' confidence combined, the better-evidenced ones counting more.

  • horizonsobject[]
  • horizons[].keyenum

    One of1w1m3m6m1y

  • horizons[].targetAtstring (date-time) | null

    The instant the fit targets (now + tYears).

  • horizons[].tYearsnumber

    The time the horizon looks ahead, in years: the average time to expiry of its markets, the more influential ones counting more, or for a synthetic horizon its target of 7, 30, 91, 182 or 365 days.

  • horizons[].medianUsdnumber

    US dollars.

  • horizons[].meanUsdnumber

    US dollars.

  • horizons[].ci50Usdany[]
  • horizons[].ci80Usdany[]
  • horizons[].ci95Usdany[]
  • horizons[].scenariosUsdobject

    The 10th, 50th and 90th percentiles.

  • horizons[].scenariosUsd.bearnumber

    US dollars.

  • horizons[].scenariosUsd.basenumber

    US dollars.

  • horizons[].scenariosUsd.bullnumber

    US dollars.

  • horizons[].sigmaAnnualnumber

    Annualized volatility of the horizon's price distribution, as a fraction (0.55 = 55%).

  • horizons[].sigmaBorrowedboolean

    The volatility came from the neighbouring horizons, because this horizon's own markets could not pin it down.

  • horizons[].syntheticboolean

    No market expires near this horizon; the fit is interpolated.

  • horizons[].confidencenumber

    Quality of the evidence behind this horizon's fit, 0..1. Not a directional view.

  • horizons[].pointCountinteger

    Strike observations in the fit.

  • horizons[].clusterCountinteger

    Distinct strike clusters among them.

  • horizons[].rmsenumber

    How far the markets' prices sit from the fitted forecast on average, in probability (0..1; lower is a closer fit).

  • horizons[].effectiveSampleSizenumber

    How many equally weighted markets the evidence is worth.

  • horizons[].keyLevelsobject[]
  • horizons[].keyLevels[].levelUsdnumber

    US dollars.

  • horizons[].keyLevels[].probabilityAbovenumber

    A rate on 0..1.

  • horizons[].densityobject[]
  • horizons[].density[].priceUsdnumber

    US dollars.

  • horizons[].density[].densitynumber
  • insightsobject[]

    Plain-language bullets computed from the run (no LLM).

  • insights[].typeenum

    driver: one of the most influential markets in a horizon, and which way it pulls the forecast. divergence: Polymarket and Kalshi disagree at the same level and horizon. delta: the featured horizon's median and confidence against the run about 24 hours earlier. new_market: an influential market that was not in that run. inconsistency: strike pairs priced out of order, which count for less. lean: the featured horizon's implied chance that Bitcoin ends above spot, when the markets lean clearly one way. note: pipeline notes and the daily up-or-down market. skew appears only in runs stored before btc-forecast/1.1.0, which replaced it with lean. New types may be added: skip ones you do not know.

  • insights[].textstring
  • insights[].refsstring[]

    The market ids the bullet is about.

  • flagsobject[]
  • flags[].typeenum

    monotonicity: a higher strike priced above a lower one on the same platform, event and expiry (both count for less). cross_platform: the platforms disagree clearly on the same strike and expiry (the shallower book counts for less).

  • flags[].detailstring
  • flags[].marketIdsstring[]
  • fanPathobject[]
  • fanPath[].atstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • fanPath[].medianUsdnumber

    US dollars.

  • fanPath[].p025Usdnumber

    US dollars.

  • fanPath[].p10Usdnumber

    US dollars.

  • fanPath[].p25Usdnumber

    US dollars.

  • fanPath[].p75Usdnumber

    US dollars.

  • fanPath[].p90Usdnumber

    US dollars.

  • fanPath[].p975Usdnumber

    US dollars.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "btc_forecast.updated",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "runAt": "2026-10-09T14:00:00.000Z",
    "spotUsd": 64500,
    "spotSource": "coingecko",
    "modelVersion": "btc-forecast/1.1.0",
    "marketCount": 500,
    "confidence": 0.8,
    "horizons": [
      {
        "key": "1w",
        "targetAt": "2026-10-16T00:00:00.000Z",
        "tYears": 0.0192,
        "medianUsd": 64300,
        "meanUsd": 64800,
        "ci50Usd": [
          62000,
          66500
        ],
        "ci80Usd": [
          59000,
          70200
        ],
        "ci95Usd": [
          56000,
          74000
        ],
        "scenariosUsd": {
          "bear": 58000,
          "base": 64300,
          "bull": 71000
        },
        "sigmaAnnual": 0.63,
        "sigmaBorrowed": false,
        "synthetic": false,
        "confidence": 0.81,
        "pointCount": 120,
        "clusterCount": 14,
        "rmse": 0.021,
        "effectiveSampleSize": 88.5,
        "keyLevels": [
          {
            "levelUsd": 70000,
            "probabilityAbove": 0.11
          }
        ]
      }
    ],
    "insights": [
      {
        "type": "note",
        "text": "Sample forecast payload."
      }
    ],
    "flags": []
  }
}

Account events#

export.completed#

Your export finished

An export you requested is ready. Sent only to your own endpoints.

data: ExportJobYour endpoints only8 attemptsv1: export.completed
Show the payload13 fields
  • idstring
  • statusenum

    One ofqueuedprocessingcompletedfailed

  • formatenum

    One ofcsvjsonparquet

  • datasetenum

    One oftradesoutcomes

  • filtersobject

    The filters the export ran with, camelCase.

  • rowCountinteger | null
  • fileSizeBytesinteger | null
  • errorstring | null

    Why a failed export failed.

  • requestedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • startedAtstring (date-time) | null
  • completedAtstring (date-time) | null
  • expiresAtstring (date-time) | null

    When the file is deleted. GET /v2/exports/{id}/download returns 410 after it.

  • downloadUrlstring | null

    Direct link to the file while the export is completed and not expired; null otherwise. Fetch it without your API key: it is on another host.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "export.completed",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "0d3c8a52-2a5b-4a61-9f0e-8a7b6c5d4e3f",
    "status": "completed",
    "format": "csv",
    "dataset": "trades",
    "filters": {
      "minAmount": 50000
    },
    "rowCount": 1234,
    "fileSizeBytes": 98765,
    "error": null,
    "requestedAt": "2026-10-09T10:00:00.000Z",
    "startedAt": "2026-10-09T10:01:00.000Z",
    "completedAt": "2026-10-09T10:01:12.000Z",
    "expiresAt": "2026-10-16T10:01:12.000Z",
    "downloadUrl": null
  }
}

export.failed#

Your export failed

An export you requested failed. Sent only to your own endpoints. (v1 sent this as export.completed with status failed.)

data: ExportJobYour endpoints only8 attemptsv1: export.completed
Show the payload13 fields
  • idstring
  • statusenum

    One ofqueuedprocessingcompletedfailed

  • formatenum

    One ofcsvjsonparquet

  • datasetenum

    One oftradesoutcomes

  • filtersobject

    The filters the export ran with, camelCase.

  • rowCountinteger | null
  • fileSizeBytesinteger | null
  • errorstring | null

    Why a failed export failed.

  • requestedAtstring (date-time)

    An instant, ISO-8601 in UTC with a Z suffix.

  • startedAtstring (date-time) | null
  • completedAtstring (date-time) | null
  • expiresAtstring (date-time) | null

    When the file is deleted. GET /v2/exports/{id}/download returns 410 after it.

  • downloadUrlstring | null

    Direct link to the file while the export is completed and not expired; null otherwise. Fetch it without your API key: it is on another host.

Example
{
  "id": "evt_01K7A0Z8M3Q4R5S6T7V8W9X0YZ",
  "type": "export.failed",
  "apiVersion": "v2",
  "createdAt": "2026-10-09T14:03:28.000Z",
  "test": false,
  "data": {
    "id": "1e4d9b63-3b6c-4b72-8a1f-9b8c7d6e5f40",
    "status": "failed",
    "format": "parquet",
    "dataset": "outcomes",
    "filters": {},
    "rowCount": null,
    "fileSizeBytes": null,
    "error": "statement timeout",
    "requestedAt": "2026-10-09T10:00:00.000Z",
    "startedAt": "2026-10-09T10:01:00.000Z",
    "completedAt": "2026-10-09T10:02:00.000Z",
    "expiresAt": null,
    "downloadUrl": null
  }
}