Migrating from v1

v2 is the current Polywhaler API. v1 is frozen and will be retired. This page maps every v1 route to its successor and lists what a client has to change.

Timeline#

v1 is deprecated

v1 was deprecated on October 16, 2026 and stops answering on April 16, 2027. After that every v1 route returns 410 gone.
  • From v2's general availability, every v1 response carries Deprecation, Sunset and a Link header pointing here and to the route's v2 successor.
  • Before the sunset, v1 is switched off for a few short, announced brownouts, so a forgotten integration fails while there is still time to fix it. Accounts still calling v1 are emailed beforehand.
  • Until then v1 gets security fixes only. Its response shapes do not change, with two exceptions: bad input answers 400 instead of 500, and /v1/btc-forecast serves the same model runs as v2, so new runs carry btc-forecast/1.1.0 and the insight type lean in place of skew (see the changelog).
  • Your keys, quota and webhook endpoints carry over: the same pwhk_ key works on both versions, and both count against one daily quota. The Usage page splits your traffic by version.

What changed#

One envelope#

Every success is {data, meta?, pagination?} and nothing else at the top level; route context that v1 mixed into the body (venue, methodology version, totals) is in meta.

One error shape#

Every error is {error: {type, code, message, param?, docUrl, requestId}}, with a fixed code catalog (API errors). Branch on code, not on the message. Every response carries X-Request-Id.

camelCase, strictly checked#

Parameters and fields are camelCase: min_amount is minAmount, event_slug is eventSlug. An unknown parameter is a 400 unknown_param (with a hint when it is the snake_case spelling) instead of being ignored, so a typo can no longer return unfiltered data.

Units#

  • Rates and probabilities are fractions from 0 to 1: a 62% win rate is 0.62. Scores (insider, Smart Money) stay 0 to 100.
  • Money is US dollars in fields ending Usd: amount is amountUsd.
  • Wallets are always a lowercase wallet (v1's proxyWallet).

Timestamps#

Times are ISO-8601 UTC strings in fields ending At (timestamp: 1791555807 becomes tradedAt: "2026-10-09T14:03:27.000Z"), and from/to take ISO-8601 instants. Days are YYYY-MM-DD.

Cursor pagination#

v1's cursor was a Unix timestamp, which skipped trades that shared a second. v2's is opaque and signed: pass pagination.nextCursor back unchanged while pagination.hasMore is true. A cursor only works with the filters it was made for. There is no count.

Key scopes#

Keys now carry scopes (read, watchlist:write, webhooks:write, exports:write). Existing keys hold all four, so nothing breaks; new keys can be read-only or restricted, and can expire.

Webhooks#

v2 endpoints are signed to the Standard Webhooks spec (webhook-id, webhook-timestamp, webhook-signature) with a whsec_ secret, so replays can be rejected and secrets rotated without downtime. Events are renamed after the resource in data (trade.high_insider is trade.insider_flagged), and data is the same shape the REST API returns. Upgrade to v2 in the portal converts an endpoint for you; see v1 endpoints.

Side by side#

GET /api/v1/trades?limit=1
{
  "data": [
    {
      "transactionHash": "0x6f1c…ddee",
      "proxyWallet": "0x5c1d…d913",
      "side": "BUY",
      "price": 0.42,
      "amount": 21000,
      "timestamp": 1791555807,
      "insiderScore": 64
    }
  ],
  "pagination": { "limit": 1, "count": 1, "nextCursor": "1791555806" }
}
GET /api/v2/trades?limit=1
{
  "data": [
    {
      "id": "0x6f1c…ddee",
      "venue": "polymarket",
      "wallet": "0x5c1d…d913",
      "side": "BUY",
      "priceProbability": 0.42,
      "amountUsd": 21000,
      "tradedAt": "2026-10-09T14:03:27.000Z",
      "insider": { "score": 64, "breakdown": { … } }
    }
  ],
  "meta": { "venue": "polymarket" },
  "pagination": { "limit": 1, "hasMore": true, "nextCursor": "eyJ2Ijox…" }
}

Route map#

Every v1 route and the v2 route that replaces it. The v2 side is what the Link: rel="successor-version" header on a deprecated v1 response points to. Details of each are in the API reference.

  • GET/api/v1/black-swan
    /api/v2/black-swanGET read
  • GET/api/v1/btc-forecast
    /api/v2/forecasts/btcGET read
  • GET/api/v1/btc-forecast/history
    /api/v2/forecasts/btc/historyGET read
  • GET/api/v1/btc-forecast/markets
    /api/v2/forecasts/btc/marketsGET read
  • GET/api/v1/clusters
    /api/v2/clustersGET read
  • GET/api/v1/consensus
    /api/v2/watchlist/consensusGET read
  • GETPOST/api/v1/exports
    /api/v2/exportsGET read, POST exports:write
  • GET/api/v1/exports/{id}
    /api/v2/exports/{id}GET read
  • GET/api/v1/leaderboard
    /api/v2/smart-money/leaderboardGET read
  • GET/api/v1/markets
    /api/v2/marketsGET read
  • GET/api/v1/openapi.json
    /api/v2/openapi.jsonGET no key
  • GET/api/v1/oracle
    /api/v2/oracleGET read
  • GET/api/v1/outcomes
    /api/v2/outcomesGET read
  • GET/api/v1/positions/aggregated
    /api/v2/positions/aggregatedGET read
  • GET/api/v1/smart-money-flow
    /api/v2/smart-money/flowGET read
  • GET/api/v1/suspicious-events
    /api/v2/insider/eventsGET read
  • GET/api/v1/trades
    /api/v2/tradesGET read
  • GET/api/v1/trades/{hash}
    /api/v2/trades/{hash}GET read
  • GET/api/v1/usage
    /api/v2/usageGET read
  • GET/api/v1/wallets/{addr}
    /api/v2/wallets/{addr}GET read
  • GET/api/v1/wallets/{addr}/cluster
    /api/v2/wallets/{addr}/clusterGET read
  • GET/api/v1/wallets/{addr}/positions
    /api/v2/wallets/{addr}/positionsGET read
  • GET/api/v1/wallets/{addr}/trades
    /api/v2/wallets/{addr}/tradesGET read
  • GETPOSTDELETE/api/v1/watchlist
    /api/v2/watchlistGET read, POST watchlist:write, DELETE watchlist:write
  • GETPOST/api/v1/webhooks
    /api/v2/webhook-endpointsGET read, POST webhooks:write
  • GETPATCHDELETE/api/v1/webhooks/{id}
    /api/v2/webhook-endpoints/{id}GET read, PATCH webhooks:write, DELETE webhooks:write
  • POST/api/v1/webhooks/{id}/test
    /api/v2/webhook-endpoints/{id}/testPOST webhooks:write

Checklist#

  1. Point your base URL at /api/v2 and rename parameters to camelCase. Unknown parameters now fail, which finds the ones you missed.
  2. Read data from the envelope, convert rates from percentages to fractions, and parse *At fields as ISO-8601.
  3. Page with the opaque cursor until hasMore is false.
  4. Handle errors by error.code, and log X-Request-Id.
  5. Upgrade each webhook endpoint to v2 and switch your receiver to the Standard Webhooks check.
  6. Watch the v1 requests in your logs drop to zero.